通过子名称获取符号的值

lov*_*ato 6 scope string-interpolation perl6 symbol-table raku

我正在创建一个包,我必须通过它在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
Run Code Online (Sandbox Code Playgroud)

然后我将'dump_value'放在一个独立的文件中,如下所示:

# somelib.pm6
unit module somelib;

sub dump_value($symbol) is export {
    say ::("$symbol")
}
Run Code Online (Sandbox Code Playgroud)
# client.pl6
#! /usr/bin/env perl6

use lib ".";
use somelib;

my $x = 10;

dump_value('$x');
Run Code Online (Sandbox Code Playgroud)

编译抱怨:

No such symbol '$x'
  in sub dump_value at xxx/somelib.pm6 (somelib) line 3
  in block <unit> at ./client.pl6 line 8
Run Code Online (Sandbox Code Playgroud)

以下是一些实验.他们都没有成功.

say ::("MY::$symbol")

say ::("OUR::$symbol")

say ::("OUTER::$symbol")

say ::("CLIENT::$symbol")
...
Run Code Online (Sandbox Code Playgroud)

那么如何修复代码呢?

更新:

谢谢!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) } ) 
}

Run Code Online (Sandbox Code Playgroud)
# client.pl6
#! /usr/bin/env perl6

use lib ".";
use somelib;

my $x = 6;
my $y = 8;

dump_value(<$x $y>);
Run Code Online (Sandbox Code Playgroud)

再次更新:

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)
}
Run Code Online (Sandbox Code Playgroud)
#! /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>);
Run Code Online (Sandbox Code Playgroud)

Håk*_*and 6

根据文件:

初始::不暗示全局.这里作为插值语法的一部分,它甚至不暗示包.插入:: (()组件后,间接名称的查找方式与原始源代码中的名称完全相同,优先级先于伪包名,然后是词法范围中的名称(搜索范围向外,以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
Run Code Online (Sandbox Code Playgroud)

要么

 CALLERS::($symbol); # Dynamic symbols in any caller's lexical scope
Run Code Online (Sandbox Code Playgroud)

请参阅包文档页面.