2015-06-16 6 views
0

Может ли кто-нибудь объяснить мне, почему переменная, объявленная в пакете, не может быть доступна функцией eval, если она не используется один раз внутри суб?
(Perl v5.16.3 MSWin32-x64-многопоточной ActiveState)perl eval Использование неинициализированного значения, объявленного в пакете

Пакет:

use strict; 
use warnings; 
package testPackage; 
my $insertVar = "TEST"; 
sub testSub { 
    my $class = shift; 
    my $test = shift; 
    eval '$test="'.$test.'";'; 
    return $test; 
} 
1; 

Программа:

use strict ; 
use warnings ; 
use testPackage ; 
my $testVar = q[insertVar = ${insertVar}] ; 
$testVar = testPackage->testSub($testVar) ; 
print "$testVar\n" ; 

Результат при выполнении программы:

Использование неинициализированного значения $ insertVar в конкатенации (.) или строки по адресу (eval 1) line 1. insertVar =

Теперь, если я использую переменную внутри testSub (например, печать):

use strict; 
use warnings; 
package testPackage; 
my $insertVar = "TEST"; 
sub testSub { 
    my $class = shift; 
    my $test = shift; 
    print $insertVar . "\n"; 
    eval '$test="'.$test.'";'; 
    return $test; 
} 
1; 

Затем программа работает точно так, как я предполагал:

TEST

insertVar = TEST

+0

Почему бы вам «eval» присвоить переменную, чтобы установить себя? – TLP

ответ

1

my переменных, объявленные в файле (за пределами фигурной скобки) выходит из области действия, когда файл заканчивает выполнение (до require и use).

$insertVar будет продолжать существовать только после того, как файл завершит выполнение, если он был захвачен суб, и он будет видимым только для субподрядчиков, которые его захватывают.

По соображениям эффективности, субподрядчики фиксируют наименьшие переменные. Если sub не ссылается на $insertVar, он не будет его фиксировать. Поскольку ваш первый testSub не ссылается на $insertVar, он не фиксирует его. Начиная с $insertVar по состоянию на тот момент, когда вы звоните , он вышел из сферы действия, он недоступен eval. Вы должны получить предупреждение Variable "$insertVar" is not available, но по неизвестным мне причинам он выдается для конкретного кода, который вы использовали.

Вашей второй testSub ссылка $insertVar, так testSub захватывает $insertVar и держит его в живых. Хотя $insertVar вышел из-под поля по вашему вызову: testSub, он доступен для eval, так как он был снят sub.

Если вы объявите переменные с помощью our, они будут глобальными переменными пакета и, следовательно, не выйдут из области действия, и они будут доступны для eval.

>perl -wE"use strict; use warnings; { my $x = 'abc'; sub foo { $x } } say foo()" 
abc 

>perl -wE"use strict; use warnings; { my $x = 'abc'; sub foo { eval '$x' } } say foo()" 
Variable "$x" is not available at (eval 1) line 2. 
Use of uninitialized value in say at -e line 1. 


>perl -wE"use strict; use warnings; { our $x = 'abc'; sub foo { eval '$x' } } say foo()" 
abc 
+0

Правильный ответ, вероятно, заключается в том, чтобы показать этому человеку, как получить доступ к переменной пакета. Это проблема XY. – TLP

+0

@TLP, я сделал, хотя вместо этого следует использовать правильную систему шаблонов. – ikegami

+0

ikegami, Принято и спасибо за ваш четкий ответ, часть о том, как переменная захватывается суб, - это ответ, который я искал. Я просто не мог понять, что здесь происходит. TLP, я знаю о «нашем», а также о том, что проблема уходит. Я предпочитаю ответ от икегами, потому что он объяснил мне, как жизненный цикл переменной в пакете работает с объявлением «мой». – Veltro

 Смежные вопросы

  • Нет связанных вопросов^_^