6

ich Pass-by-reference tue wie folgt aus:Gibt es eine bessere Möglichkeit, per Referenz in Perl zu übergeben?

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 saubere Art und Weise, es zu tun?

Prototypen funktionieren nicht, weil ich eine Funktionsreferenz verwende (vertraue mir, dass es einen guten Grund gibt, eine Funktionsreferenz zu verwenden).

Ich möchte auch nicht $_[0] überall in repl verwenden, weil es hässlich ist.

Antwort

9

Haben Sie bei Data::Alias geschaut? Sie können lexikalische Aliasnamen mit einer sauberen Syntax erstellen.

Sie können es verwenden Pass-by-reference Semantik wie diese zu erstellen:

use strict; 
use warnings; 

use Data::Alias; 

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

my $count = 0; 

foo($count); 

print "$count\n"; 

Der Ausgang ist 1, was darauf hinweist, dass der Anruf zu foo ihr Argument geändert.

+0

Leider schaute ich auf die "Implementierung" -Abschnitt der Dokumentation ... ack! Ich nehme an, dieses Modul ist irgendwie wie Würstchen ... viel mehr Spaß, wenn Sie nicht wissen, wie sie gemacht sind ... :) – JoelFan

+0

@JoelFan: yup. Dies ist sehr viel ein "Versuchen Sie es nicht zu Hause" -Modul :) –

+0

beginnt "Dieses Modul verwendet keinen Quellfilter" und geht einfach von da ab ... :) – JoelFan

3

Es gibt mehrere Möglichkeiten, dies zu tun. Übergeben Sie explizit einen Skalarref an $foo, oder nutzen Sie Perls integrierte Semantik für die Weitergabe durch Verweis.

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 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->(@_); 
} 

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

Der erste Einsatz normale Perl harte Referenzen den Job zu erledigen .

Die ref-Methode zum ersten Durchlauf verwendet die Tatsache, dass Perl Argumente an alle Funktionen als Referenzen übergibt. Die Elemente von @_ sind tatsächlich Aliase zu den Werten in der Argumentliste, wenn das Unterprogramm aufgerufen wird. Indem Sie $_[0] in foo() ändern, ändern Sie tatsächlich das erste Argument zu foo().

Der zweite Durchlauf von Ref-Methode verwenden die Tatsache, dass ein Sub mit einem & Sigil und keine Parens ruft die @_ Array seines Aufrufers. Ansonsten ist es identisch.

Update: Ich bemerkte gerade, dass Sie wünschen, $_[0] zu vermeiden. Sie können dies in repl tun, wenn Sie wollen:

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

danke ... gute info, aber ich will "implizit" pass-by-ref – JoelFan

3

 

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

oder 'my ($ line) = \ (@_);' –

+0

@Sinan - hätte nicht gedacht, dass das funktionieren würde. Jeden Tag etwas Neues lernen. – mob

+1

Regel siehe http://perldoc.perl.org/perlref.html#Making-References "Als besonderen Fall gibt' \ (@ foo) '' eine Liste von Referenzen auf den Inhalt von '@ foo' zurück, keine Referenz zu "@ foo" selbst. " –

0

Ich glaube nicht, dass es etwas falsch ist local mit der Verwendung des Alias ​​in diesem Fall zu erstellen.

Dynamischer Bereich ist natürlich eine mächtige Funktion, aber solange Sie die Nebenwirkungen kennen (neuer Wert ist in Funktionen sichtbar, die von seinem Bereich aufgerufen werden, wenn ein Lexikon mit demselben Namen im Bereich ist, kann es ' t lokalisiert werden, ...) dann ist es eine sinnvolle Ergänzung zu der bereits übergelaufenen Perl-Toolbox.

Der Hauptgrund für die Warnungen in den Perl Dokumenten über local ist, Leute davon abzuhalten, sie versehentlich anstelle von my zu verwenden und den Übergang von perl4 zu erleichtern. Aber es gibt definitiv Zeiten, in denen local ist nützlich, und das ist einer.

Verwenden Sie for, um Ihren Alias ​​zu erstellen, ist auch eine Option, aber ich finde die explizite Syntax mit local klarer in seiner Absicht. Es ist auch ein bisschen schneller, wenn Leistung ein Anliegen ist.