Eval возвращаемое значение - PullRequest
0 голосов
/ 30 августа 2011

Это правильный код?

my $ttt = eval {
 my @a=(1,2);
 return \@a;
};

print @$ttt[1]. "\n";

Я думал, что блок eval вычисляется на лету и не существует после выполнения. Есть ли минусы в этом решении?

Ответы [ 3 ]

3 голосов
/ 30 августа 2011

Блок eval остается частью кода в памяти.Это то, что вы пытаетесь избежать?Если это так, это неправильный способ сделать это, и вам следует объяснить больше основной проблемы, которую вы пытаетесь решить.

Код будет выполняться, но вы используете фрагмент массива в печати, где вывероятно, намереваетесь использовать простое разыменование массива:

print $$ttt[1]. "\n";

Вы также не проверяете, успешно ли прошло eval;Следующее переходит к печати, а затем (если у вас включены предупреждения) выдает предупреждение Использование неинициализированного значения:

my $ttt = eval {
    die "horribly";
    my @a=(1,2);
    return \@a;
};

print @$ttt[1]. "\n";
3 голосов
/ 30 августа 2011

Использование eval бесполезно, и вы не проверяете результат, но у меня есть ощущение, что вы пытаетесь понять, что на самом деле не имеет ничего общего с eval, но когда переменные освобождены.

Perl использует подсчет ссылок, чтобы знать, когда безопасно освобождать переменную. Переменная освобождается, как только на нее ничего не ссылается. В дополнение к ссылкам на лексические (my) переменные также ссылается область, в которой они созданы, а на переменные пакета также ссылается пакет, в котором они находятся.

При "нормальных" обстоятельствах переменная будет уничтожена при выходе из области видимости, поскольку будет удалена единственная ссылка на нее *. Области видимости создаются многими вещами, включая фигурные скобки и eval. Вот пример:

use feature qw( say );

{ package D; DESTROY { say "Destroyed $_[0]"; } }

{
    my $x = bless({}, 'D');   # $x's refcnt is 1.
    say "Before scope exit";
}                             # $x's refcnt drops to 0, so it's freed.
say "After scope exit";

Выход:

Before scope exit
Destroyed D=HASH(0x8eff768)
After scope exit

А что если вы сохранили ссылку на $x вне области, в которой находится $x?

use feature qw( say );

{ package D; DESTROY { say "Destroyed $_[0]"; } }

my $ref;
{
    my $x = bless({}, 'D');   # $x's refcnt is 1.
    $ref = \$x;               # $x's refcnt is 2.
    say "Before scope exit";
}                             # $x's refcnt drops to 1, so it's not freed.
say "After scope exit";
$ref = undef;                 # $x's refcnt drops to 0, so it's freed.
say "After clearing reference";

Выход:

Before scope exit
After scope exit
Destroyed D=HASH(0x8cc4768)
After clearing reference

В вашем коде возвращенная ссылка на @a поддерживает @a в действии даже после выхода из созданной области. Это можно проверить, напечатав $ttt, а затем @$ttt.

ARRAY(0x99464b8)
1 2

Если вы вводите блок несколько раз, вы получаете ссылки на разные переменные, потому что my выделяет новую переменную каждый раз *. Сравнить

my @a;
for (1..2) {
    my $x = $_;
    push @a, \$x;
}
say $a[0];  # 1

с

my @a;
my $x;
for (1..2) {
    $x = $_;
    push @a, \$x;
}
say $a[0];  # 2

* & mdash; Реализация отличается от этого объяснения, но это оптимизация, которая не предполагает видимых побочных эффектов.

3 голосов
/ 30 августа 2011

Блок eval анализируется с остальной частью кода, и его возвращаемое значение является ссылкой на массив @a. Эта ссылка присваивается $ttt. Пока блок eval выходит из области видимости, @a по-прежнему имеет ненулевой счетчик ссылок (благодаря $ttt), поэтому он все еще существует.

...