关于Raku中EVAL中哈希绑定的问题

在 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;
#!/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;

输出:

这有效:

#!/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;
#!/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-binding-works.raku 
Hash::Test.new(hash => {: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::Test 不是我正在使用的真正类,而是我打高尔夫球的目的。谁能解释一下这里发生了什么?谢谢!

回答

TL;DR 通过隐式声明no strict;符自动声明变量。通过绑定到具有相同名称的隐式包符号的隐式词法变量声明符来声明包变量。您的代码破坏了这种绑定,从而破坏了您的代码。要解决它,请换一种方式说同样的话。ourourmy

解决方案

no strict;没有帮助,所以我们摆脱了它。也一样our。相反,我们声明一个my 词法变量,用它做我们需要/可以做的一切,然后,在将是EVALd的代码的末尾,创建一个包变量并将它绑定到存储在词法中的值。

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变量并遵循此 SO 中显示的逻辑。所以这段代码:

no script;
%hash-test := ...;

是这样做的:

(my %hash-test := $?PACKAGE.WHO<%hash-test>) := ...;

它创建了一个词法 %hash-test符号和一个 %hash-test符号,并将它们绑定在一起——这种绑定对于our变量的正常运行是必不可少的——然后立即打破这种基本绑定。

此后,无论您的代码的其余部分做什么,它只对变量的词法 %hash-test版本进行处理,使符号版本%hash-test高而干燥,以便稍后自动激活为空哈希。


正如 jnthn 在我开头链接的 SO 下面的评论中所说:

我们当然可以警告绑定到our变量是没有意义的

但目前没有警告。


正如您在下面的评论中所解释的那样,当您尝试使用%hash-test is Hash::Test编译器时,神秘地决定您已经编写了“连续两个术语”。正如我在评论中所解释的那样,这是由于上述诡计,当您our使用通常的语法(或隐式地使用no strict;)声明变量时。


要解决以上所有问题,请忘记no strict;,忘记使用our,而是:

  • 使用词法来完成设置值的工作;
  • 通过创建包符号OUR::<%hash-test>并将其绑定到词法的值来结束。

    以上是关于Raku中EVAL中哈希绑定的问题的全部内容。
    THE END
    分享
    二维码
    < <上一篇
    下一篇>>