Jus*_*Guy 9 namespaces string-interpolation raku
我正在尝试使用插值在另一个命名空间中创建一个变量,但在咨询https://docs.raku.org/language/packages#index-entry-::()后无法使其工作。在测试不同的东西时,我发现了一些让我感到困惑的东西。这有效:
#!/usr/bin/env raku
$Foo::bar = 'foobar';
say $Foo::bar;
Run Code Online (Sandbox Code Playgroud)
#!/usr/bin/env raku
$Foo::bar = 'foobar';
say $Foo::bar;
Run Code Online (Sandbox Code Playgroud)
但这不是:
#!/usr/bin/env raku
my $bar = 'bar';
$Foo::($bar) = 'foobar';
say $Foo::bar;
Run Code Online (Sandbox Code Playgroud)
$ ./package-interpolate.raku
No such symbol '$bar'
in block <unit> at ./package-interpolate.raku line 4
Run Code Online (Sandbox Code Playgroud)
我错过了什么吗?谢谢!
rai*_*iph 11
TL;DR对于保存在某个特定包(命名空间)中的变量(符号)的引用,有三种不同的语法。您尝试了两个,但看起来您可能需要第三个。这里也有一些皱纹,所以这个答案很长。
这是三种语法的摘要,从可能是(部分)您想要的语法开始,然后是您尝试过的两种:
Foo::Bar::Baz::<$qux>
静态指定包,动态指定变量
如果嵌套包规范无法解析为相应的一组现有包,则该构造会生成错误。如果包规范解析,则如果变量被分配或绑定到并且不存在,则创建该变量。
$Foo::Bar::Baz::qux
静态指定的包和变量
如果嵌套包规范中的任何包无法解析为现有包,则会自动创建该包。如果变量被分配或绑定到并且不存在,也会创建该变量。
::('$Foo::Bar::Baz::qux')
动态指定的包和变量
如果嵌套包规范无法解析为相应的一组现有包,或者如果变量不存在,则该构造会生成错误。
此答案的其余部分是三个部分,其中包含与上述内容相对应的更多详细信息。
Foo::Bar::Baz::<$qux>如果所有包都已经存在,则构造将起作用,如果变量不存在,则创建变量。否则构造将产生一个错误,在编译时是一个合理的错误(如果只指定了一个包)或在运行时是一个 LTA 错误(如果指定了嵌套包)。
可以通过在运行时计算其值的表达式/变量间接指定变量名称。
引用本节标题中链接的文档:
要在不扫描的情况下直接在包的符号表中查找,请将包名称视为散列
这是第一个示例,其中我们引用了非嵌套不存在的包中不存在的变量:
my $bar = '$baz';
say Foo::{$bar};
Run Code Online (Sandbox Code Playgroud)
产生编译时错误:
Undeclared name:
Foo used at line 2
Run Code Online (Sandbox Code Playgroud)
接下来,一组嵌套的不存在的包中的一个不存在的变量:
my $bar = '$baz';
try say Foo::Bar::Baz::{$bar};
say $!; # Could not find symbol '&Baz' in 'GLOBAL::Foo::Bar'
say GLOBAL::Foo::Bar; # (Bar)
Run Code Online (Sandbox Code Playgroud)
错误消息(保存在 中的异常$!)不仅仅是 LTA,而是反映了疯狂。并且构造已经创建了包GLOBAL::Foo::Bar。更疯狂!
现在的例子中,我们引用一个包,不存在和在其内的变量,它不最初存在:
package Foo {}
my $bar = '$qux';
say Foo::{$bar}; # (Any)
say Foo::{$bar}:exists; # False
Foo::{$bar} = 99;
say Foo::{$bar}:exists; # True
say Foo::{$bar}; # 99
say Foo.WHO.keys; # ($qux)
say $Foo::qux; # 99
Run Code Online (Sandbox Code Playgroud)
因此,Foo::{...}语法(或Foo::<...>,但不是::(...))并没有报错了,如果指定的变量不存在,而是只有当程序包不存在。
此语法中对不存在的变量(在存在的包中)的引用将返回(Any). 如果(Any)分配给它,它会创建变量。
(除非包是MY或未指定,这在此语法中意味着相同的事情。如果MY缺少查找的变量,查找将返回值Nil而不是(Any),并且不能分配或绑定到。)
$Foo::Bar::Baz::qux如果你提到一个使用这种语法的包,即使是一个非嵌套的包,如果它不存在,你就会创建它。
如果您分配/绑定到一个变量,如果它不存在,您将创建它。
您必须静态声明要指定的(嵌套)包和变量名称。您不能间接说明(例如通过变量)此语法的任何部分。
引用本节标题中链接的文档:
普通的包限定名称看起来像这样:
$Foo::Bar::quux,这将是$quux包中的变量Foo::Bar
这是您问题中的第一个代码片段(对@user0721090601 很惊讶),并附加了一些行。三行的块显示了Foo包的位置(并提供了对本答案和文档中涵盖的三种语法的先睹为快)。最后一行确认$bar变量已添加到Foo包中:
$Foo::bar = 'foobar';
say $Foo::bar; # foobar
say GLOBAL::Foo; # (Foo) Package qualified name yields type object `(Foo)`
say GLOBAL::<Foo>; # (Foo) Package qualified lookup (yields same object)
say ::('Foo'); # (Foo) Package scanning lookup (yields same object)
say GLOBAL::Foo.WHO.keys; # ($bar) `.WHO` returns `(Foo)`'s package named `Foo`
Run Code Online (Sandbox Code Playgroud)
GLOBAL是包含“解释器范围的包符号,真的”的“伪”包UNIT::GLOBAL。
如果删除上面代码中的第一行 ( $Foo::bar = 'foobar';):
该say $Foo::bar;行的结果是(Any);
添加的三行代码块继续显示(Foo),表明仅在语法形式中提及一个变量$Foo::bar就足以创建包Foo;
最后一行显示(),这表明$bar是不添加到Foo,尽管包装say $Foo::bar;显示线(Any),而不是Nil。
::('$Foo::Bar::Baz::qux')如果要读取或写入现有变量现有的包,毫无意外地创建他们,如果他们不存在的危险,使用此语法。
相反,如果您希望自动创建包和/或变量,请使用其他两种语法之一或其他一些方法。
您可以在(...)此语法的一部分中使用复杂的表达式,它们将被动态插入,但随后将它们视为静态源代码。因此,你可以做的事情等,包括文字串'$Foo::Bar::Baz::qux'在(...),或一个变量,计算结果为这样的字符串,并且编译器将其插入总的参考,其随后用来引导查找,处理之间的每个分量::S作为独特的嵌套包。
引用本节标题中链接的文档:
使用
::($expr)您通常放置包或变量名称的位置......查找间接名称......首先优先引导伪包名称,然后是词法范围内的名称(向外搜索范围,以 CORE 结尾) )。最后搜索当前包。
注意,查找将扫描过很多的包。
您问题中的第二个代码片段(它不像您预期的那样工作)使用此扫描逻辑进行变量查找,可能不仅查找一个明确指定的包,还查找许多包。
这是相同的代码,但在开头插入了另一行:
package Foo { our $bar } # <-- This line added
my $bar = 'bar';
$Foo::($bar) = 'foobar';
say $Foo::bar; # foobar
Run Code Online (Sandbox Code Playgroud)
现在它起作用了。
这表明您的$Foo::($bar) = 'foobar';线路:
看着用于可变$bar在封装Foo。(因此,“插入名称”确实“如文档所宣传的”那样工作。)
但并没有创建一个包。
而且也没有创建一个变量。
但是确实做了分配,因为查找成功找到了与查找匹配的包和变量。