C'è un modo migliore per passare per riferimento in Perl?
-
20-09-2019 - |
Domanda
Sto facendo il pass-by-reference in questo modo:
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);
Esiste un modo più pulito per farlo?
I prototipi non funzionano perché sto utilizzando un riferimento a una funzione (credetemi, c'è una buona ragione per utilizzare un riferimento a una funzione).
Inoltre non voglio usarlo $_[0]
ovunque dentro repl
perché è brutto.
Soluzione
Hai guardato? Dati::Alias?Ti consente di creare alias con ambito lessicale con una sintassi pulita.
Puoi usarlo per creare una semantica pass-by-reference come questa:
use strict;
use warnings;
use Data::Alias;
sub foo {
alias my ($arg) = @_;
$arg++;
}
my $count = 0;
foo($count);
print "$count\n";
L'uscita è 1
, indicando che la chiamata a foo
ha modificato la sua argomentazione.
Altri suggerimenti
sub repl {
my $line = \$_[0]; # or: my $line = \shift
$$line = "new value";
}
Ci sono un paio di modi per farlo. Esplicitamente passare un ref scalari di $foo
, o approfittare del pass integrata a Perl da semantica di riferimento.
riferimento esplicito:
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);
}
Passo di Riferimento:
my $foo = "old value";
doRepl( \&repl, $foo );
print $foo; # prints "new value";
sub repl {
$_[0] = "new value";
}
sub doRepl {
my $replFunc = shift;
$replFunc->(@_);
}
Anche amatore passaggio per riferimento:
my $foo = "old value";
doRepl( \&repl, $foo );
print $foo; # prints "new value";
sub repl {
$_[0] = "new value";
}
sub doRepl {
my $replFunc = shift;
&$replFunc;
}
Il primo uso normale perl riferimenti difficile da fare il lavoro.
Il primo passaggio con il metodo ref utilizza il fatto che Perl passa gli argomenti a tutte le funzioni come riferimenti. Gli elementi di @_
sono effettivamente alias ai valori dell'argomento lista quando la subroutine viene chiamata. Alterando $_[0]
in foo()
, è effettivamente modificare il primo argomento a foo()
.
Il secondo passaggio dal metodo ref utilizzare il fatto che un sub chiamato con un sigillo &
e senza parentesi ottiene l'array @_
del suo chiamante. Altrimenti è identica.
Aggiornamento: Ho appena notato il desiderio di evitare di $_[0]
. È possibile farlo in repl se si desidera:
sub repl {
for my $line( $_[0] ) {
$line = 'new value';
}
}
Non credo che ci sia qualcosa di sbagliato con l'utilizzo local
per creare l'alias in questo caso.
scope dinamico è, naturalmente, una potente funzionalità, ma fino a quando si è a conoscenza degli effetti collaterali (nuovo valore è visibile nelle funzioni chiamate dal suo campo di applicazione, se un lessicale con lo stesso nome è di portata, non può essere localizzato, ...) allora è un utile aggiunta alla già traboccante Perl toolbox.
Il motivo principale per le avvertenze nella documentazione Perl circa local
sono per tenere la gente inavvertitamente usarlo al posto di my
e per facilitare la transizione da perl4. Ma ci sono sicuramente momenti in cui local
è utile, e questo è uno.
Utilizzando for
per creare il tuo alias è anche un'opzione, ma trovo la sintassi esplicita con local
più chiaro nel suo intento. E 'anche un po' più veloce se le prestazioni sono una preoccupazione.