关于 Raku 中 EVAL 中哈希绑定的问题
Question About Hash Binding in EVAL in Raku
我 运行 遇到了一些我无法理解的事情,即在 EVAL 中绑定散列。在 EVAL 之外绑定散列按预期工作。 EVAL 中的未绑定散列按预期工作。但是在 EVAL 中绑定散列并不能像我预期的那样工作。 (我的期望可能是错误的。)这是代码:
这个有效:
#!/usr/bin/env raku
class Hash::Test does Associative {
has %.hash;
multi method STORE(@pairs) {
for @pairs -> $pair {
self.STORE: $pair
}
}
multi method STORE(Pair $pair) {
%!hash{$pair.key} = $pair.value;
}
}
no strict;
%hash-test := Hash::Test.new;
%hash-test = foo => 'bar', baz => 'quux';
say %hash-test;
输出:
$ ./hash-binding-works.raku
Hash::Test.new(hash => {:baz("quux"), :foo("bar")})
这有效:
#!/usr/bin/env raku
class Foo {
use MONKEY-SEE-NO-EVAL;
method eval(Str $code) {
EVAL $code;
}
}
my $code = q:to/END/;
no strict;
%hash = foo => 'bar', baz => 'quux';
END
Foo.eval: $code;
say %Foo::hash;
输出:
$ ./hash-EVAL-works.raku
{baz => quux, foo => bar}
但这不起作用:
#!/usr/bin/env raku
class Hash::Test does Associative {
has %.hash;
multi method STORE(@pairs) {
for @pairs -> $pair {
self.STORE: $pair
}
}
multi method STORE(Pair $pair) {
%!hash{$pair.key} = $pair.value;
}
}
class Foo {
use MONKEY-SEE-NO-EVAL;
method eval(Str $code) {
EVAL $code;
}
}
my $code = q:to/END/;
no strict;
%hash-test := Hash::Test.new;
%hash-test = foo => 'bar', baz => 'quux';
say %hash-test;
END
no strict;
Foo.eval: $code;
say %Foo::hash-test;
输出:
$ ./hash-EVAL-does-not-work.raku
Hash::Test.new(hash => {:baz("quux"), :foo("bar")})
{}
Hash::Test 不是我正在使用的真正的 class,而是我使用它的结果。谁能解释这里发生了什么?谢谢!
TL;DR no strict;
autodeclares package variables via an implicit our
declarator。 our
通过隐式 my
词法 变量声明符声明包变量,该声明符绑定到具有相同名称的隐式包符号。您的代码破坏了该绑定,而这也破坏了您的代码。要修复它,请换一种说法。
解决方案
no strict;
没有帮助,所以我们摆脱了它。 our
也是如此。相反,我们声明一个 my
lexical 变量,做我们 need/can 所做的一切,然后,在代码的末尾将是 EVAL
d,创建一个包变量并将其绑定到词法中存储的值。
my $code = q:to/END/;
my %hash is Hash::Test;
%hash = foo => 'bar', baz => 'quux';
OUR::<%hash-test> := %hash;
END
Foo.eval: $code;
say %Foo::hash-test; # Hash::Test.new(hash => {:baz("quux"), :foo("bar")})
惊喜的解释
在 no strict;
下没有显式声明符声明的变量隐式声明 our
个变量:
no strict;
%hash-test = :a;
say MY::<%hash-test>; # {a => True}
say OUR::<%hash-test>; # {a => True}
换句话说,上面前两行的净效果相当于:
our %hash-test = :a;
反过来,our
个变量隐式声明 my
个变量并遵循 中所示的逻辑。所以这段代码:
no script;
%hash-test := ...;
正在这样做:
(my %hash-test := $?PACKAGE.WHO<%hash-test>) := ...;
创建一个 lexical %hash-test
符号和一个 package %hash-test
符号,并绑定它们 - - 哪个绑定 必不可少 our
变量的正常运行 - 然后立即 打破 那个必不可少的绑定。
此后,无论您的其余代码做什么,它都只针对变量的 词法 %hash-test
版本,留下 包 %hash-test
的符号版本又高又干,所以它稍后会自动生成一个空哈希。
正如 jnthn 在我开头链接的 SO 下方的评论中所说:
We certainly could warn that binding to an our
variable is pointless
但是目前没有警告。
正如您在下面的评论中解释的那样,当您尝试使用 %hash-test is Hash::Test
时,编译器神秘地决定您已经写了“连续两个术语”。正如我在评论中解释的那样,这是由于当您使用通常的语法(或隐式地使用 no strict;
)声明一个 our
变量时造成的上述欺骗。
要解决以上所有问题,忘记 no strict;
,忘记使用 our
,而是:
使用词法来设置值;
通过使用 OUR::<%hash-test>
创建包符号并将其绑定到词法的值来结束。
我 运行 遇到了一些我无法理解的事情,即在 EVAL 中绑定散列。在 EVAL 之外绑定散列按预期工作。 EVAL 中的未绑定散列按预期工作。但是在 EVAL 中绑定散列并不能像我预期的那样工作。 (我的期望可能是错误的。)这是代码:
这个有效:
#!/usr/bin/env raku
class Hash::Test does Associative {
has %.hash;
multi method STORE(@pairs) {
for @pairs -> $pair {
self.STORE: $pair
}
}
multi method STORE(Pair $pair) {
%!hash{$pair.key} = $pair.value;
}
}
no strict;
%hash-test := Hash::Test.new;
%hash-test = foo => 'bar', baz => 'quux';
say %hash-test;
输出:
$ ./hash-binding-works.raku
Hash::Test.new(hash => {:baz("quux"), :foo("bar")})
这有效:
#!/usr/bin/env raku
class Foo {
use MONKEY-SEE-NO-EVAL;
method eval(Str $code) {
EVAL $code;
}
}
my $code = q:to/END/;
no strict;
%hash = foo => 'bar', baz => 'quux';
END
Foo.eval: $code;
say %Foo::hash;
输出:
$ ./hash-EVAL-works.raku
{baz => quux, foo => bar}
但这不起作用:
#!/usr/bin/env raku
class Hash::Test does Associative {
has %.hash;
multi method STORE(@pairs) {
for @pairs -> $pair {
self.STORE: $pair
}
}
multi method STORE(Pair $pair) {
%!hash{$pair.key} = $pair.value;
}
}
class Foo {
use MONKEY-SEE-NO-EVAL;
method eval(Str $code) {
EVAL $code;
}
}
my $code = q:to/END/;
no strict;
%hash-test := Hash::Test.new;
%hash-test = foo => 'bar', baz => 'quux';
say %hash-test;
END
no strict;
Foo.eval: $code;
say %Foo::hash-test;
输出:
$ ./hash-EVAL-does-not-work.raku
Hash::Test.new(hash => {:baz("quux"), :foo("bar")})
{}
Hash::Test 不是我正在使用的真正的 class,而是我使用它的结果。谁能解释这里发生了什么?谢谢!
TL;DR no strict;
autodeclares package variables via an implicit our
declarator。 our
通过隐式 my
词法 变量声明符声明包变量,该声明符绑定到具有相同名称的隐式包符号。您的代码破坏了该绑定,而这也破坏了您的代码。要修复它,请换一种说法。
解决方案
no strict;
没有帮助,所以我们摆脱了它。 our
也是如此。相反,我们声明一个 my
lexical 变量,做我们 need/can 所做的一切,然后,在代码的末尾将是 EVAL
d,创建一个包变量并将其绑定到词法中存储的值。
my $code = q:to/END/;
my %hash is Hash::Test;
%hash = foo => 'bar', baz => 'quux';
OUR::<%hash-test> := %hash;
END
Foo.eval: $code;
say %Foo::hash-test; # Hash::Test.new(hash => {:baz("quux"), :foo("bar")})
惊喜的解释
在 no strict;
下没有显式声明符声明的变量隐式声明 our
个变量:
no strict;
%hash-test = :a;
say MY::<%hash-test>; # {a => True}
say OUR::<%hash-test>; # {a => True}
换句话说,上面前两行的净效果相当于:
our %hash-test = :a;
反过来,our
个变量隐式声明 my
个变量并遵循
no script;
%hash-test := ...;
正在这样做:
(my %hash-test := $?PACKAGE.WHO<%hash-test>) := ...;
创建一个 lexical %hash-test
符号和一个 package %hash-test
符号,并绑定它们 - - 哪个绑定 必不可少 our
变量的正常运行 - 然后立即 打破 那个必不可少的绑定。
此后,无论您的其余代码做什么,它都只针对变量的 词法 %hash-test
版本,留下 包 %hash-test
的符号版本又高又干,所以它稍后会自动生成一个空哈希。
正如 jnthn 在我开头链接的 SO 下方的评论中所说:
We certainly could warn that binding to an
our
variable is pointless
但是目前没有警告。
正如您在下面的评论中解释的那样,当您尝试使用 %hash-test is Hash::Test
时,编译器神秘地决定您已经写了“连续两个术语”。正如我在评论中解释的那样,这是由于当您使用通常的语法(或隐式地使用 no strict;
)声明一个 our
变量时造成的上述欺骗。
要解决以上所有问题,忘记 no strict;
,忘记使用 our
,而是:
使用词法来设置值;
通过使用
OUR::<%hash-test>
创建包符号并将其绑定到词法的值来结束。