6

que estoy haciendo el paso por referencia así:¿Hay una mejor manera de pasar por referencia en Perl?

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); 

¿Hay una forma más limpia de hacerlo?

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

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

Respuesta

9

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

Se puede utilizar para crear la semántica pase por referencia así:

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, lo que indica que la llamada a foo modificó su argumento.

+0

Desafortunadamente, miré la sección "Implementación" de los documentos ... ¡ack! Supongo que este módulo es como salchichas ... mucho más divertido si no sabes cómo se hacen ... :) – JoelFan

+0

@JoelFan: yup. Este es en gran medida un módulo "No intente esto en casa" :) –

+0

comienza "Este módulo no usa un filtro de fuente" y simplemente va cuesta abajo a partir de ahí ... :) – JoelFan

3

Hay un par de formas de hacerlo. Pase explícitamente una referencia escalar a $foo, o aproveche el paso incorporado de Perl por 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); 
} 

Pasar 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 pase más elegante por referencia: referencias duras

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

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

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

El primero de ellos el uso de Perl normal a hacer el trabajo .

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

El segundo método de pase por ref utiliza el hecho de que un sub llamado con un sigil & y sin parens obtiene el arreglo @_ de su llamador. De lo contrario, es idéntico.

Actualización: Acabo de notar que desea evitar $_[0]. Puede hacer esto en repl si lo desea:

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

gracias ... buena información, pero quiero "paso a paso" implícito – JoelFan

3

 

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

o 'mi ($ línea) = \ (@_);' –

+0

@Sinan - no habría supuesto que eso funcionaría. Aprendiendo algo nuevo cada día. – mob

+1

rule ver http://perldoc.perl.org/perlref.html#Making-References "Como un caso especial,' \ (@ foo) 'devuelve una lista de referencias a los contenidos de' @ foo', no una referencia a '@ foo' en sí mismo". –

0

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

El alcance dinámico es, por supuesto, una característica poderosa, pero siempre que conozca los efectos secundarios (el nuevo valor es visible en funciones llamadas desde su ámbito, si hay un léxico del mismo nombre en alcance). t ser localizado, ...) entonces es una adición útil a la ya desbordante caja de herramientas Perl.

La razón principal de las advertencias en los documentos de Perl sobre local es evitar que la gente la use inadvertidamente en lugar de my y facilitar la transición de perl4. Pero definitivamente hay momentos en los que local es útil, y este es uno.

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

Cuestiones relacionadas