Pergunta

Estou fazendo uma referência como esta:

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

Existe uma maneira mais limpa de fazer isso?

Os protótipos não funcionam porque estou usando uma referência de função (confie em mim que há um bom motivo para usar uma referência de função).

Eu também não quero usar $_[0] em todos os lugares repl Porque é feio.

Foi útil?

Solução

Você já olhou Data :: Alias? Ele permite criar aliases de escopo lexicamente com uma sintaxe limpa.

Você pode usá-lo para criar semânticas de passagem por referência como esta:

use strict;
use warnings;

use Data::Alias;

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

my $count = 0;

foo($count);

print "$count\n";

A saída é 1, indicando que a chamada para foo modificou seu argumento.

Outras dicas

 

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

Há algumas maneiras de fazer isso. Passar explicitamente um ref. $foo, ou aproveite o passe interno de Perl pela semântica de referência.

Referência explícita:

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

Passe por referência:

my $foo = "old value";
doRepl( \&repl, $foo );
print $foo; # prints "new value";

sub repl {
    $_[0] = "new value";
}

sub doRepl {
    my $replFunc = shift;
    $replFunc->(@_);
}

Até o passe mais sofisticado por referência:

my $foo = "old value";
doRepl( \&repl, $foo );
print $foo; # prints "new value";

sub repl {
    $_[0] = "new value";
}

sub doRepl {
    my $replFunc = shift;
    &$replFunc;
}

O primeiro usa referências duras normais de Perl para fazer o trabalho.

A primeira passagem pelo método REF usa o fato de que Perl passa argumentos a todas as funções como referências. Os elementos de @_ são realmente aliases para os valores na lista de argumentos quando a sub -rotina é chamada. Alterando $_[0] dentro foo(), você realmente altera o primeiro argumento para foo().

O segundo passe pelo método Ref use o fato de que um sub -chamado com um & sigil e nenhum parens recebe o @_ matriz de seu chamador. Caso contrário, é idêntico.

Atualizar: Acabei de notar que você deseja evitar $_[0]. Você pode fazer isso em Repl se quiser:

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

Eu não acho que há nada de errado em usar local Para criar o alias neste caso.

O escopo dinâmico é obviamente uma característica poderosa, mas desde que você esteja ciente dos efeitos colaterais (o novo valor é visível nas funções chamadas de seu escopo, se um lexical do mesmo nome estiver no escopo, não pode ser localizado, ...) Então é uma adição útil para a caixa de ferramentas Perl já transbordante.

A principal razão para os avisos no perl docs sobre local devem impedir as pessoas de usá -lo inadvertidamente em vez de my e para facilitar a transição do Perl4. Mas definitivamente há momentos em que local é útil, e este é um.

Usando for Para criar seu alias também é uma opção, mas acho a sintaxe explícita com local mais claro em sua intenção. Também é um pouco mais rápido se o desempenho for uma preocupação.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top