【问题标题】:Get a symbol's value by its name in a sub通过 sub 中的名称获取符号的值
【发布时间】:2019-02-04 16:15:23
【问题描述】:

我正在制作一个包,我必须在 sub 中通过其名称获取符号的值,而该符号是在 sub 之外定义的。

这是简化的代码,它按预期工作:

#! /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”放入另一个 sub 之后,它不再起作用了!

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

【问题讨论】:

  • 以下对我有用:say CALLER::MY::($symbol)

标签: scope raku string-interpolation symbol-table


【解决方案1】:

根据the documentation

首字母 :: 并不意味着全局。这里作为插值的一部分 语法它甚至不暗示包。插值后 ::() 组件,查找间接名称就好像它有 在原源代码中出现过,优先考虑 前导伪包名称,然后是词法范围内的名称 (向外搜索范围,以 CORE 结尾)。

所以当你在somelib 包中的dump_value() 中写入say ::("$symbol") 时,它会首先在当前范围内查找$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

the package documentation page

【讨论】:

  • 很抱歉再次打扰您,但请查看底部的更新。
  • 没问题!试试OUTER::CALLERS::CALLERS::($^id)
  • doc 表示:CALLERS 表示Dynamic symbols in **any** caller's lexical scope。那么为什么它需要两个 CALLERS 呢?我认为一个就足够了。
  • 我不确定,可能是错误或我错过的东西。也许这里的一些专家可以回答这个问题?我同意这还不清楚,我也会调查一下..
【解决方案2】:

几件事:

use lib ".";
use somelib;
our $x = 10;     # You need to export the value into the global scope
dump_value('$x');

然后,使用global scope

unit module somelib;

sub dump_value($symbol) is export {
    say GLOBAL::("$symbol")
}

【讨论】:

  • 感谢您的回答。要求用户使用“我们的”有点烦人。
  • @lovetomato 很好,它表明它可能会用于其他词法范围,这就是它现在所做的。
  • 很抱歉再次打扰您,但请查看底部的更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-17
  • 2018-10-20
  • 1970-01-01
  • 2017-03-01
  • 2016-03-26
  • 1970-01-01
  • 2019-05-13
相关资源
最近更新 更多