Gibt es eine bessere Möglichkeit, in Perl per Referenz zu übergeben?
-
20-09-2019 - |
Frage
Ich mache Pass-by-Reference so:
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);
Gibt es eine sauberere Möglichkeit?
Prototypen funktionieren nicht, weil ich eine Funktionsreferenz verwende (glauben Sie mir, es gibt einen guten Grund für die Verwendung einer Funktionsreferenz).
Ich möchte es auch nicht verwenden $_[0]
überall in repl
weil es hässlich ist.
Lösung
Hast Du Dir angesehen Daten::Alias?Damit können Sie Aliase mit lexikalischem Gültigkeitsbereich und einer sauberen Syntax erstellen.
Sie können damit eine Pass-by-Reference-Semantik wie folgt erstellen:
use strict;
use warnings;
use Data::Alias;
sub foo {
alias my ($arg) = @_;
$arg++;
}
my $count = 0;
foo($count);
print "$count\n";
Die Ausgabe ist 1
, was darauf hinweist, dass der Anruf an foo
hat sein Argument geändert.
Andere Tipps
sub repl {
my $line = \$_[0]; # or: my $line = \shift
$$line = "new value";
}
Es gibt ein paar Möglichkeiten, dies zu tun. geben Explizit einen skalaren ref $foo
, oder nutzen Sie die Perl-Einbau-Pass von Referenzsemantik.
Ausdrücklich:
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 durch Verweis:
my $foo = "old value";
doRepl( \&repl, $foo );
print $foo; # prints "new value";
sub repl {
$_[0] = "new value";
}
sub doRepl {
my $replFunc = shift;
$replFunc->(@_);
}
Auch ausgefallenere Pass von Referenz:
my $foo = "old value";
doRepl( \&repl, $foo );
print $foo; # prints "new value";
sub repl {
$_[0] = "new value";
}
sub doRepl {
my $replFunc = shift;
&$replFunc;
}
Die erste Einsatz normale Perl harte Referenzen die Arbeit zu tun.
Der erste Durchlauf durch ref Verfahren nutzt die Tatsache, dass Perl gibt Argumente zu allen Funktionen, als Referenzen. Die Elemente sind tatsächlich @_
Aliase auf die Werte in der Argumentenliste, wenn die Subroutine aufgerufen wird. Durch die Veränderung $_[0]
in foo()
, ändern Sie eigentlich das erste Argument foo()
.
Der zweite Durchlauf durch ref Verfahren nutzen die Tatsache, dass ein mit einem Unter &
Sigill genannt und keine Pars die @_
Array seines Aufrufers wird. Ansonsten ist es identisch.
Update: Ich habe gerade bemerkt, dass Sie zu vermeiden $_[0]
wünschen. Sie können dies in repl tun, wenn Sie wollen:
sub repl {
for my $line( $_[0] ) {
$line = 'new value';
}
}
Ich glaube nicht, dass an der Verwendung etwas auszusetzen ist local
um in diesem Fall den Alias zu erstellen.
Der dynamische Bereich ist natürlich eine leistungsstarke Funktion, aber solange Sie sich der Nebenwirkungen bewusst sind (neuer Wert ist in Funktionen sichtbar, die aus seinem Bereich aufgerufen werden, wenn sich ein Lexikon mit demselben Namen im Bereich befindet, kann er nicht lokalisiert werden, ...) dann ist es eine sinnvolle Ergänzung zur ohnehin schon überfüllten Perl-Toolbox.
Der Hauptgrund für die Warnungen in den Perl-Dokumenten ist local
sollen verhindern, dass Menschen es versehentlich verwenden my
und um den Übergang von Perl4 zu erleichtern.Aber es gibt definitiv Zeiten, in denen local
ist nützlich, und das ist eines.
Benutzen for
Das Erstellen Ihres Alias ist ebenfalls eine Option, aber ich finde die explizite Syntax mit local
klarer in seiner Absicht.Es ist auch etwas schneller, wenn es auf die Leistung ankommt.