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.

War es hilfreich?

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top