Прототип: вернуть либо массив, либо скаляр

У меня проблемы с пониманием того, как вернуть массив с помощью прототипа подпрограммы. Вот пример

sub f (&@) {
        my ($func) = @_;        
        eval &$func;
}

my $a = f {return 1};
my @b = f {return (2,1,1,4)};

print "a = ".$a."\n";
print "b = ".scalar(@b)."\n";

Это выводы a = 1 а также b = 1, но я ожидаю @b иметь длину четыре.

Я также пытался вернуть ссылку \ eval &$func в функции f, Я могу тогда разыменовать скаляр ($$a 1), но при разыменовании массива (@$b) Perl говорит мне, что это не ссылка на массив.

2 ответа

Решение

Прототипы не влияют на то, возвращает ли подпрограмма скаляр или список. использование wantarray если вы хотите знать, в каком контексте была вызвана подпрограмма.

eval &$func;

В строке выше сначала вызывается подпрограмма, на которую ссылается $func в скалярном контексте затем преобразует свое возвращаемое значение в строку и выполняет эту строку как программу Perl.

sub f (&) {
    my ($func) = @_;
    eval { &$func }
}

Это будет делать то, что вы, очевидно, хотите (вызвать подпрограмму, на которую ссылается $func в том же контексте (скаляр или список), в котором f сам был назван, в пределах eval блок для отлова ошибок во время выполнения).

sub f (&) {
    my ($func) = @_;
    eval { $func->(@_) }
}

Это более современный стиль, с -> оператор.

Не нужно оценивать, вы можете

use warnings;
sub f (&) {
    my ($func) = @_;
    $func->(); # better than &$func
}

eval с другой стороны, возвращает только последний элемент в списке, заданном $f как то же самое, что писать eval scalar $func->();, так @b заканчивается одним элементом => 4

Из perldoc -f eval

возвращаемое значение EXPR анализируется и выполняется, как если бы это была небольшая Perl-программа. Значение выражения (которое само определяется в скалярном контексте) сначала анализируется, и, если ошибок не было, выполняется как блок в лексическом контексте текущей программы Perl.

Другие вопросы по тегам