在阅读了Raku留档后,我发现这只是为了取消定义一个变量。我相信在Raku中赋值和绑定之间存在差异。
定义和取消定义标量很容易。
> my $n
(Any)
> $n.defined
False
> $n = 3
3
> $n.defined
True
> $n = Nil
(Any)
> $n.defined
False
当变量被绑定时,这是不可能的。
> my $k := 5
5
> $k := Nil
===SORRY!=== Error while compiling:
Cannot use bind operator with this left-hand side
at line 2
------> <BOL>⏏<EOL>
> $k = Nil
Cannot assign to an immutable value
in block <unit> at <unknown file> line 1
对于数组或哈希,我可以清空它,但变量仍然是定义的。
对于函数,当您使用sub
定义函数时,您不能取消定义它,但可以使用匿名函数。
> my &pera = -> $n { $n + 2}
-> $n { #`(Block|140640519305672) ... }
> &pera = Nil
(Callable)
> &pera.defined
False
> my &pera = -> $n { $n + 2}
-> $n { #`(Block|140640519305672) ... }
> &pera = Nil
(Callable)
> &pera.defined
False
> sub foo ($n) { $n + 1}
&foo
> &foo.defined
True
> &foo = Nil
Cannot modify an immutable Sub (&foo)
in block <unit> at <unknown file> line 1
那么赋值和绑定有什么区别呢?
如何取消定义变量?
这里有很多不同的问题要讨论。
> my $k := 5;
> $k := Nil;
Cannot use bind operator
第一个问题是Raku REPL。参见您的SO。您尝试过CommaIDE或repl.it?
您的代码完全有效:
my $k := 5;
$k := Nil;
say $k; # Nil
继续前进:
my $k := 5;
$k = Nil;
Cannot assign to an immutable value
这是不同的。将5
绑定到$k
后,$k=Nil
代码正在尝试为数字赋值。只有容器[1]支持赋值。数字不是容器,因此您不能将其赋值。
澄清您提到但未明确涵盖的一些案例:
my @foo;
@foo := Nil;
Type check failed in binding; expected Positional...
虽然标量变量(带有$
sigil的变量)将绑定到任何值或容器,但@
sigil'd变量将仅绑定到位置
容器,例如Array
。(同样,%
到Associative
,例如Hash
。)
不仅如此,这些容器始终是定义的。因此,即使它们为空,它们仍然为返回
:True
。定义
my @foo := Array.new; # An empty array
say @foo.elems; # 0 -- zero elements
say @foo.defined; # True -- despite array being empty
现在将Nil
分配给数组:
my @foo;
@foo = Nil;
say @foo; # [(Any)]
如果@
sigil'd变量的声明没有将其绑定到某个显式位置
类型,则它会绑定到@
变量的默认选项。这是一个Array
,默认元素值为任何
。
上面的@foo=Nil;
语句将一个Nil
值分配给@foo
的第一个元素。将一个值分配给多元素容器的一个不存在的元素意味着一个新的Scalar
容器突然出现,并在分配继续之前绑定到那个丢失的元素上。然后,因为我们分配了一个Nil
,并且因为Nil
表示没有值,Array
的默认值((任何)
)被复制到Scalar
而不是Nil
中。
关于sub
case…
sub foo {}
&foo = {} # Cannot modify an immutable Sub (&foo)
&foo := {} # Cannot use bind operator ...
而sub foo
声明会生成
解绑或取消定义变量
你不能解除变量的绑定,让它们完全不受任何约束。(换句话说,Raku避免了十亿美元的错误。)在某些情况下,你可以重新绑定变量。
在某些情况下,您可以将未定义的值绑定或分配给变量。如果它不是标量变量,那么这就像上面介绍的@
变量示例。接下来考虑标量情况。
装订案例的一个例子:
my $foo := Any;
say $foo.defined; # False
say $foo; # (Any)
say $foo.VAR.WHAT; # (Any)
我们将看到是什么。VAR
一会儿就好。
分配案例:
my $foo = Any;
say $foo.defined; # False
say $foo.WHAT; # (Any)
say $foo.VAR.WHAT; # (Scalar)
重要的是要理解,在这种情况下,$foo
绑定到Scalar
,这是一个容器,对于“定义”的某些定义,它肯定是“定义”的,尽管在中出现了相反的情况,比如$foo.定义;
行。
在say$foo. What;
行中,Scalar
保持隐藏。相反,我们看到了一个(任何)
。但是(任何)
是绑定到$foo
的Scalar
容器中保存的值的类型。
在下一行中,我们开始通过调用来揭开面纱。
。$foo
上的VAR. What。VAR
让Scalar
显示自己,而不是产生它包含的值。所以我们看到了类型Scalar
。
但是如果你在那个Scalar
上调用.定义
,它仍然坚持隐藏!:
my $foo;
say $foo.VAR.defined; # False
say $foo.VAR.DEFINITE; # True
(迫使Raku告诉你其确定性观点的最终真相的唯一方法是调用确定性的最终仲裁者。DEFINITE
。)
如果根据原始变量声明这样做是有效的,编译器将允许您将给定的新值或容器分配或绑定到变量。
分配或绑定未定义的值遵循相同的规则。
所有变量都必须受其声明末尾的约束。
如果变量的声明允许将未定义的值绑定/分配给该变量,则该变量可以在这个意义上是未定义的。但在所有其他情况和意义上,变量本身永远不能“未绑定”或“未定义”。
绑定是关于使变量对应于某个容器或值:
>
带有@
和%
符号的变量必须绑定到容器(分别为默认Array
和Hash
)。
带有$
符号的变量必须绑定到容器(默认Scalar
)或值。
带有的变量
赋值意味着将值复制到容器中。
如果一个变量绑定到一个容器,那么你可以赋值给它,前提是编译器根据原始变量声明允许赋值。
如果变量未绑定到容器,则编译器将拒绝对其进行赋值。
如果您将标量容器用作值,那么您将获得保存在容器内的值。
将值(已定义或未定义)绑定到标量变量将意味着它将停止充当容器。如果您随后尝试分配给该变量,它将不起作用。您需要将其重新绑定回容器。
[1]在这个答案中,我使用了“容器”一词来指代任何可以用作包含其他值的容器的值。例如,Array
、Hash
或Scalar
的实例。