Pasando una referencia escalar en Perl
Pregunta
Sé que pasar un escalar a un submarino está pasando la referencia, pero como soy nuevo en Perl, todavía hice la siguiente prueba:
#!/usr/bin/perl
$i = 2;
subr(\$i);
sub subr{
print $_[0]."\n";
print $$_[0]."\n";
}
Pensé que la primera línea va a imprimir una dirección y la segunda línea le devolverá el número, pero la segunda es una línea en blanco. Me señaló alguien más para hacer esto: ${$_[0]}
Y imprime el número. Pero ella no sabía la razón por la que sin {} no funciona y por qué está funcionando con {}. Entonces, ¿qué ha pasado?
Solución
Es porque su segunda declaración de impresión es equivalente a hacer esto ...
my $x = $$_; print $x[0];
Cuando lo que quieres es
my $x = $_[0]; print $$x;
En otras palabras, la eliminación de referencias ocurre antes de evaluar el subíndice de matriz.
Cuando agrega esas casas curlas, le dice a Perl cómo interpretar la expresión como lo desea; evaluará $_[0]
Primero, y luego desreferencia para obtener el valor.
Otros consejos
Es una cosa de orden de evaluación.
$$_[0] is evaluated as {$$_}[0]
Este es el elemento 0 de la referencia de la variable escalar $ _. Primero toma la referencia y luego está tratando de encontrar el elemento 0.
${$_[0]}
Esta es una referencia al elemento 0 de la matriz @_. Primero encontrará el elemento 0 y luego tomando una referencia de eso.
Si te configuras use strict
y use warnings
En la parte superior de su código, verá muchas advertencias sobre valores indefinidos de su primer intento.
$$_[0]
es como $foo[0]
, solo con $ _ en lugar del nombre de la matriz. Esto significa que $ _ se trata como una referencia de matriz, y la expresión no implica la referencia escalar $_[0]
en absoluto. $_->[0]
es equivalente, utilizando la alternativa ->
sintaxis. La sintaxis para la deserencia puede parecer arbitraria y difícil de recordar, pero hay sentido y orden subyacente; Una muy buena presentación es en http://perlmonks.org/?node=references+quick+Reference.
No tienes que pasar una referencia a $i
. La notación $_[0]
es un alias por $i
Cuando lo invocas como subr( $i )
.
use strict;
use warnings;
use Test::More tests => 2;
sub subr{ $_[0]++ } # messing with exactly what was passed first
my $i=2;
is( $i, 2, q[$i == 2] );
subr($i);
is( $i, 3, q[$i == 3] );
Otro ejemplo es este:
use strict;
use warnings;
use Test::More tests => 6;
use Test::Exception;
sub subr{ $_[0]++ }
my $i=2;
is( $i, 2, q[$i == 2] );
subr($i);
is( $i, 3, q[$i == 3] );
sub subr2 { $_[0] .= 'x'; }
dies_ok { subr2( 'lit' ); } 'subr2 *dies* trying to modify a literal';
lives_ok {
my $s = 'lit';
subr2( $s );
is( $s, 'litx', q[$s eq 'litx'] );
subr2(( my $s2 = 'lit' ));
is( $s2, 'litx', q[$s2 eq 'litx'] );
} 'subr2 lives with heap variables';
Producción:
ok 1 - $i == 2
ok 2 - $i == 3
ok 3 - subr2 *dies* trying to modify a literal
ok 4 - $s eq 'litx'
ok 5 - $s2 eq 'litx'
ok 6 - subr2 lives with heap variables
1..6