除了 lizmat 的出色答案之外,解释这里发生的事情可能与此相关。
当你说 my $foo 时,你实际上是在说 my Any $foo。1 当你说 my @foo 时,你是在隐含地说更接近 my Any @foo 的东西,这是一样的作为my Array[Any] $foo(但在位置容器中)。这使您可以将任何内容放入数组中,因为它的类型是Any。
当您访问一个未定义的对象时,它会返回一个未定义的值——但该值仍然是类型化的。只是碰巧默认情况下,类型是Any。然而,我们可以改变一些东西,它可能会变得更清楚:
my Str $foo;
say $foo; # a Str that's undefined, so '(Str)';
my $bar; # implicitly typed Any
say $bar; # an Any that's undefined, so '(Any)';
my Int @foo = 0, 1, 2;
say @foo[0]; # an Int defined as 0, so '0'
say @foo[1]; # an Int defined as 1, so '1'
say @foo[3]; # an Int that's undefined, so '(Int)'
正如 lizmat 在她的回答中指出的那样,(Type) 是 .gist 方法的默认表示,.say 使用该方法表示未定义的值。2
他们不返回 Nil 的原因是因为根据定义,Nil 为调用它的每个方法返回 Nil(除了一些例外,如 Bool,它返回 False)—它有点像 Objective-C 的nil。但是未定义的类型对象仍然有用途:例如,您仍然可以在其上调用方法,只要它们不访问属性。有时这可能是一个非常有用的属性,它实际上使您能够执行以下操作:
my Foo $foo .= new;
什么是语法糖
my Foo $foo;
$foo = $foo.new;
$foo 是一个未定义类型的对象,所以我们实际上还是调用了Foo.new。
- 正如 raiph 在 cmets 中正确指出的那样,我应该注意到这不是 确切正在发生的事情,但从最终用户的角度来看,这已经足够接近并且不那么复杂了。李>
- 人们总是可以覆盖它,我已经为我的一些类做了这个,这些类的名称可疑地接近或与添加明确前缀的内置函数相同,因此我不会混淆它们。