Pregunta

Estoy haciendo un paso por referencia así:

use strict;
use warnings;

sub repl {
    local *line = \$_[0]; our $line;
    $line = "new value";
}

sub doRepl {
    my ($replFunc) = @_;
    my $foo = "old value";
    $replFunc->($foo);
    print $foo; # prints "new value";
}

doRepl(\&repl);

¿Existe una forma más limpia de hacerlo?

Los prototipos no funcionan porque estoy usando una referencia de función (créame, hay una buena razón para usar una referencia de función).

Yo tampoco quiero usar $_[0] en todas partes en repl porque es feo.

¿Fue útil?

Solución

¿Has mirado Datos::Alias?Le permite crear alias de ámbito léxico con una sintaxis limpia.

Puedes usarlo para crear una semántica de paso por referencia como esta:

use strict;
use warnings;

use Data::Alias;

sub foo {
    alias my ($arg) = @_;
    $arg++;
}

my $count = 0;

foo($count);

print "$count\n";

La salida es 1, indicando que la llamada a foo modificó su argumento.

Otros consejos

sub repl {
    my $line = \$_[0];     # or: my $line = \shift
    $$line = "new value";
}

Hay un par de maneras de hacer esto. Explícitamente pasar una ref escalar a $foo, o tomar ventaja de paso incorporado en Perl por la semántica de referencia.

referencia explícita:

my $foo = "old value";
doRepl( \&repl, \$foo );
print $foo; # prints "new value";

sub repl {
    my $line = shift;
    $$line = "new value";
}

sub doRepl {
    my ($replFunc, $foo) = @_;
    $replFunc->($foo);
}

Pass por referencia:

my $foo = "old value";
doRepl( \&repl, $foo );
print $foo; # prints "new value";

sub repl {
    $_[0] = "new value";
}

sub doRepl {
    my $replFunc = shift;
    $replFunc->(@_);
}

Incluso más elegante pase por referencia:

my $foo = "old value";
doRepl( \&repl, $foo );
print $foo; # prints "new value";

sub repl {
    $_[0] = "new value";
}

sub doRepl {
    my $replFunc = shift;
    &$replFunc;
}

Las primeras referencias de un uso normal de Perl duros para hacer el trabajo.

La primera pasada por el método de ref utiliza el hecho de que Perl pasa argumentos a todas las funciones como referencias. Los elementos de @_ son en realidad falsas Para los valores en la lista de argumentos cuando la subrutina se llama. Al alterar $_[0] en foo(), en realidad se altera el primer argumento de foo().

El segundo pase por el método de ref utilizar el hecho de que un sub llamada con un sigilo & y no hay parens obtiene la matriz @_ de su llamador. De lo contrario, es idéntico.

Actualización: Me he dado cuenta de que el deseo de evitar $_[0]. Puede hacer esto en repl si quieres:

sub repl {
    for my $line( $_[0] ) {
        $line = 'new value';
    }
}

No creo que haya nada malo con el uso local para crear el alias en este caso.

alcance dinámico es, por supuesto, una característica de gran alcance, pero siempre y cuando usted es consciente de los efectos secundarios (nuevo valor es visible en las funciones llamadas de su ámbito, si un léxico del mismo nombre está en el ámbito, no puede ser localizada, ...), entonces es una adición útil a la ya desbordante caja de herramientas Perl.

La razón principal de las advertencias en la documentación de Perl sobre local son para evitar que la gente sin querer usarlo en lugar de my y para facilitar la transición de perl4. Pero definitivamente hay momentos en los que local es útil, y este es uno.

El uso de for para crear su alias es también una opción, pero me parece que la sintaxis explícita con local más claro en su intención. También es un poco más rápido si el rendimiento es una preocupación.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top