Получить значение символа по его имени в подпрограмме
Я делаю пакет, где я должен получить значение символа по его имени в подпрограмме, в то время как символ определен вне подпрограммы.
Вот упрощенный код, он работает как ожидалось:
#! /usr/bin/env perl6
sub dump_value($symbol) {
say ::("$symbol")
}
# usage:
my $x = 10;
dump_value('$x');
# expected output: 10
# actual output: 10
Затем я помещаю "dump_value" в отдельный файл, как показано ниже:
# somelib.pm6
unit module somelib;
sub dump_value($symbol) is export {
say ::("$symbol")
}
# client.pl6
#! /usr/bin/env perl6
use lib ".";
use somelib;
my $x = 10;
dump_value('$x');
Компилятор пожаловался:
No such symbol '$x'
in sub dump_value at xxx/somelib.pm6 (somelib) line 3
in block <unit> at ./client.pl6 line 8
Ниже приведены некоторые эксперименты. Ни одному из них не удалось.
say ::("MY::$symbol")
say ::("OUR::$symbol")
say ::("OUTER::$symbol")
say ::("CLIENT::$symbol")
...
Так как исправить код?
ОБНОВИТЬ:
Спасибо! CALLERS::($symbol)
решил мою первоначальную проблему. Но в немного более сложной ситуации компилятор снова пожаловался:
# somelib.pm6
unit module somelib;
sub dump_value(@symbols) is export {
# output: 6
say CALLERS::('$x');
# error: No such symbol 'CALLERS::$x'
say @symbols.map({ CALLERS::($^id) } )
}
# client.pl6
#! /usr/bin/env perl6
use lib ".";
use somelib;
my $x = 6;
my $y = 8;
dump_value(<$x $y>);
ОБНОВЛЕНИЕ СНОВА:
использование OUTER::CALLERS::($^id)
,
ОБНОВЛЕНИЕ СНОВА И СНОВА:
После того, как я поместил "dump_value" в другую подпрограмму, он больше не работал!
# somelib.pm6
unit module somelib;
sub dump_value(@symbols) is export {
say @symbols.map({ OUTER::CALLERS::($^id) } )
}
sub wrapped_dump_value(@symbols) is export {
dump_value(@symbols)
}
#! /usr/bin/env perl6
use lib ".";
use somelib;
my $x = 6;
my $y = 8;
# ouput: (6 8)
dump_value(<$x $y>);
# error: No such symbol 'OUTER::CALLERS::$x'
wrapped_dump_value(<$x $y>);
3 ответа
Согласно документации:
Начальный:: не подразумевает глобальный. Здесь, как часть синтаксиса интерполяции, он даже не подразумевает пакет. После интерполяции компонента::() косвенное имя ищется точно так же, как если бы оно было в исходном исходном коде, причем приоритет отдается сначала именам псевдопакетов, а затем именам в лексической области (поиск выходит наружу, заканчиваясь на CORE).
Поэтому, когда вы пишете say ::("$symbol")
в dump_value()
в somelib
пакет, он будет сначала искать $symbol
в текущей области, которая имеет значение '$x'
тогда попробуй посмотреть $x
(также в текущей области видимости), но переменная $x
определяется в лексической области действия вызывающего, поэтому вы получите No such symbol '$x'
ошибка.
Вы можете обратиться к лексическому символу вызывающего абонента, заданному значением $symbol
используя либо:
CALLER::MY::($symbol); # lexical symbols from the immediate caller's lexical scope
или же
CALLERS::($symbol); # Dynamic symbols in any caller's lexical scope
dump_value('CALLER::MY::$x'); # works with your lib as it is
Другие ответы объясняют, что происходит.
Пара вещей:
use lib ".";
use somelib;
our $x = 10; # You need to export the value into the global scope
dump_value('$x');
Затем используйте глобальную область видимости:
unit module somelib;
sub dump_value($symbol) is export {
say GLOBAL::("$symbol")
}