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.

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top