Вопрос

Я делаю передачу по ссылке следующим образом:

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

Есть ли более чистый способ сделать это?

Прототипы не работают, потому что я использую ссылку на функцию (поверьте мне, что для использования ссылки на функцию есть веская причина).

Я также не хочу использовать $_[0] повсюду в repl потому что это уродливо.

Это было полезно?

Решение

Вы смотрели на Данные::Псевдоним?Это позволяет вам создавать псевдонимы с лексической областью действия с чистым синтаксисом.

Вы можете использовать его для создания семантики передачи по ссылке, подобной этой:

use strict;
use warnings;

use Data::Alias;

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

my $count = 0;

foo($count);

print "$count\n";

Результатом является 1, указывающий на то , что вызов к foo изменил свой аргумент.

Другие советы

 

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

Есть несколько способов сделать это.Явно передайте скалярную ссылку в $foo, или воспользуйтесь встроенной в Perl семантикой передачи по ссылке.

Явная ссылка:

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

Передать по ссылке:

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

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

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

Еще более прихотливый переход по ссылке:

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

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

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

Первый использует обычные жесткие ссылки perl для выполнения этой работы.

Метод first pass by ref использует тот факт, что Perl передает аргументы всем функциям в качестве ссылок.Элементы @_ фактически являются псевдонимами значений в списке аргументов при вызове подпрограммы.Путем изменения $_[0] в foo(), вы фактически изменяете первый аргумент на foo().

Второй метод pass by ref использует тот факт, что sub, вызываемый с & символ и никакие скобки не получают @_ массив его вызывающего абонента.В остальном это идентично.

Обновить: Я только что заметил твое желание избежать $_[0].Вы можете сделать это в repl, если хотите:

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

Я не думаю, что есть что-то неправильное в использовании local чтобы создать псевдоним в этом случае.

Динамическая область видимости, конечно, является мощной функцией, но до тех пор, пока вы знаете о побочных эффектах (новое значение отображается в функциях, вызываемых из его области видимости, если лексика с тем же именем находится в области видимости, она не может быть локализована, ...), то это полезное дополнение к уже переполненному набору инструментов Perl.

Основная причина предупреждений в Perl docs о local должны удерживать людей от непреднамеренного использования его вместо my и облегчить переход с perl4.Но определенно бывают моменты, когда local полезен, и это один из них.

Используя for создать свой псевдоним тоже можно, но я нахожу явный синтаксис с local яснее в своем намерении.Это также немного быстрее, если речь идет о производительности.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top