重新约束的规则是什么? [英] What are the rules for re-binding?

查看:15
本文介绍了重新约束的规则是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

[注意:我是根据Rakudo的旧版本提出这个问题的。正如the accepted answer中所解释的,令人困惑的输出是have now been resolvedRakudo错误的结果。我已将以下问题的原始版本留作历史参考。]

Raku有时禁止重新绑定;以下两行

sub f($a) { $a := 42 }
my var = 'foo'; var := 'not-foo';

生成编译时错误:

===SORRY!=== Error while compiling 
Cannot use bind operator with this left-hand side

然而,Raku允许在很多情况下重新绑定--包括很多让我大吃一惊的情况。以下全部成功重新绑定;每say输出not-foo

my Any a = 'foo';
say a := 'not-foo';
my Any $b := 'foo';
say $b := 'not-foo';
my @c := ('foo', 'foo');
say @c := ('not-foo', 'not-foo');
my @d is List = ('foo', 'foo');
say @d := ('not-foo', 'not-foo');
my %e := (:foo<foo>);
say %e := (:not-foo<not-foo>);

sub fn1(Any a) { a := 'not-foo';  say a  }
fn1 'foo';
sub fn2(Any $b) { $b := 'not-foo'; say $b }
fn2 'foo';
sub fn3(@c) {  @c := ('not-foo', 'not-foo'); say @c }
fn3 ('foo', 'foo');
sub fn4(+@d) { @d := ('not-foo', 'not-foo'); say @d }
fn4 ('foo', 'foo');
sub fn5(@d is raw) { @d := ('not-foo', 'not-foo'); say @d }
fn5 ('foo', 'foo');

my ($one-foo, $two-foo) := ('foo', 'foo');
$one-foo := 'not-foo';
say $one-foo;

my foo = 'foo';
say MY::<foo> := 'not-foo';
sub foo-fn { 'foo' }
MY::<&foo-fn> := { 'not-foo' }
say foo-fn;

my $absolutely-foo = 'foo';
sub fn6 { CALLER::<$absolutely-foo> := 'not-foo';}
fn6;
say $absolutely-foo;

因此,如果满足以下条件之一,则当前似乎允许对任何名称进行重新绑定,而不考虑签名或缺少签名:

  1. 名称具有任何显式类型约束(包括Any@%符号施加的类型约束),或
  2. 重新绑定使用限定名称。
当前声明的变量和参数都会发生这种重新绑定,并且包括不是rwcopy的参数。正如上一个示例所示,它甚至允许以如下方式重新绑定(似乎是这样的?)违反词法范围。(该示例基于a Roast test,注释为-- legal?,这表明我可能并不是唯一发现这种行为令人惊讶的人!尽管测试重新绑定了is dynamic变量--在某些方面,上面的行为甚至更令人惊讶)。

据我所知,唯一不能使用这些方法之一重新绑定的名称是声明为constant的名称。

所以四个问题:

  1. 我对当前行为的描述正确吗?[编辑:即,我上面列出的两个规则是否正确地描述了当前行为,或者正确的描述是否需要其他/其他规则?]
  2. 该行为是否正确/故意/符合规范?(尽管存在S03-binding,但我发现关于Re绑定的内容非常少)。
  3. 如果此行为不是故意的,有关重新绑定的规则应该是什么?
  4. 有什么方法可以告诉Raku";不要将此名称重新绑定到新值,不是真正的意思(&I)?

(这个问题取代了my earlier question,在我意识到重新绑定名称是多么容易之前,我问了它;我将关闭它以支持这个问题。另一个相关问题:Is there a purpose or benefit in prohibiting sigilless variables from rebinding?,与上面的几个示例相反,该问题讨论了一些设计权衡,其前提是无符号变量不能重新绑定。)

推荐答案

我在问题中问到的不一致行为是由Rakudo错误造成的--Rakudo在某些不应该允许重新绑定的情况下允许重新绑定。此错误已在Rakudo/Rakudo#4536中解决。

此决议后,重新绑定的规则为:

  • Sigilless "variables"不能被反弹(并且不能被重新赋值,因此它们不是真正的变量&q;)
  • 带符号的变量通常可以重新绑定,但以下例外情况除外。
  • 如果带符号的变量是Signature的一部分,则它不能被反弹,除非通过is copy or is rw traits声明为可绑定。
    • 这适用于函数的签名(因此sub f($a) { $a := 42 }是非法的)
    • 它也适用于使用:=作为变量声明的一部分进行去结构化的签名。例如在my ($var1, $var2) := ('foo', 'bar')中,右侧是签名,因此$var1$var2无法反弹。

应用这些规则意味着现在禁止以下所有重新绑定(在提出问题时允许):

my Any a = 'foo';
say a := 'not-foo';

sub fn1(Any a) { a := 'not-foo';  say a  }
fn1 'foo';
sub fn2(Any $b) { $b := 'not-foo'; say $b }
fn2 'foo';
sub fn3(@c) {  @c := ('not-foo', 'not-foo'); say @c }
fn3 ('foo', 'foo');
sub fn4(+@d) { @d := ('not-foo', 'not-foo'); say @d }
fn4 ('foo', 'foo');
sub fn5(@d is raw) { @d := ('not-foo', 'not-foo'); say @d }
fn5 ('foo', 'foo');

my ($one-foo, $two-foo) := ('foo', 'foo');
$one-foo := 'not-foo';
say $one-foo;

相反,应用这些规则意味着(正确地)允许问题中显示的其他一些重新绑定:

my Any $b := 'foo';
say $b := 'not-foo';
my @c := ('foo', 'foo');
say @c := ('not-foo', 'not-foo');
my @d is List = ('foo', 'foo');
say @d := ('not-foo', 'not-foo');
my %e := (:foo<foo>);
say %e := (:not-foo<not-foo>);
最后,问题中显示的一些示例涉及修改(pseudo) package的内容。这允许重新绑定,否则将被上述规则禁止:

my foo = 'foo';
say MY::<foo> := 'not-foo';
sub foo-fn { 'foo' }
MY::<&foo-fn> := { 'not-foo' }
say foo-fn;

my $absolutely-foo = 'foo';
sub fn6 { CALLER::<$absolutely-foo> := 'not-foo';}
fn6;
say $absolutely-foo;

然而,就像使用the Metaobject Protocol访问私有方法/属性一样,使用伪包来破坏Raku的正常规则应该是一个极端的last resort,并且不享受与Raku的其他方面相同的稳定性保证。

这篇关于重新约束的规则是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆