我可以在 Nil 上调用任何方法,这感觉不对

jja*_*jja 14 raku

我最近花了很多时间调试一个脚本,当我最终发现问题时,是因为代码看起来像这样:

class Foo {
    has $.bar;
    method () {
        # do stuff
        $!.bar;
    }
}
Run Code Online (Sandbox Code Playgroud)

原来,问题是与$!.bar,它应该是要么$!bar$.bar。我明白了。

但这为什么不死

详细看这个,它看起来像这里的问题是,我试图调用(不存在)的方法bar$!,它在这一点上Nil,因为再也没有出现过任何差错。

看起来我实际上可以调用我想要的任何方法,Nil并且它们都默默地返回Nil,包括像Nil.this-is-a-fake-method和这样的东西Nil.reverse-entropy(123)

这是一个功能吗?如果是这样,理由是什么?

hob*_*bbs 13

是的,它是有意并记录在案的。标题Nil是“缺少值或良性失败”,类文档中提到

Nil不存在的方法的任何方法调用,以及因此的任何下标操作,都将成功并返回Nil

say Nil.ITotallyJustMadeThisUp;  # OUTPUT: «Nil?» 
say (Nil)[100];                  # OUTPUT: «Nil?» 
say (Nil){100};                  # OUTPUT: «Nil?»
Run Code Online (Sandbox Code Playgroud)

概要 2指出“任何未定义的方法调用Nil返回Nil,以便Nil向下传播方法调用链。同样的任何对Nil返回的下标操作Nil”,因此意图似乎是允许表达式,例如$foo.Bar()[0].Baz()不需要Nil在每一步检查,或特殊的“无安全” " 方法调用和下标运算符。

  • 的确。很久以前也已经:https://github.com/rakudo/rakudo/commit/174727377f(2013 年 12 月)另请参阅相关推测:https://design.raku.org/S02.html#Nil (4认同)
  • `Nil` 类有一个 `FALLBACK` https://docs.raku.org/language/typesystem#index-entry-FALLBACK_(method) 方法,该方法返回 `Nil`。基本上,在由于找不到方法而引发异常之前,会检查“FALLBACK”,并在可用时调用。 (2认同)

chr*_*mis 5

这个问题(以及 hobbs 的回答)也让我感到……不安:我最终找到了https://docs.raku.org/language/traps:它解释了分配Nil会产生不同的值,通常是Any。以下基本的 REPL 交互也演示了这一点:

> my $foo = Nil
(Any)

> $foo.bar
No such method 'bar' for invocant of type 'Any'
  in block <unit> at <unknown file> line 1

> my $bar := Nil
Nil

> $bar.baz
Nil
Run Code Online (Sandbox Code Playgroud)

((此处介绍=和之间的区别:=https : //docs.raku.org/language/containers#Binding))

...所以一般的想法是,常规代码中的“缺失值或良性失败”远没有我(也许你也是?)突然担心的那样普遍:但是,当您要使用正则表达式时,它确实会发生直接匹配并在与直接调用$!.

这让我更加了解Nil和之间的区别Any,并且提供的基本原理对我来说更有意义。

  • `Nil` 将容器设置为其默认状态。您可以更改默认值。`我的 $foo 是默认值(42) = 5;` `$foo = Nil;` `说 $foo; #42` (2认同)