【问题标题】:I can call any method on Nil and this feels wrong我可以在 Nil 上调用任何方法,这感觉不对
【发布时间】:2020-05-26 01:25:15
【问题描述】:

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

class Foo {
    has $.bar;
    method () {
        # do stuff
        $!.bar;
    }
}

原来问题出在$!.bar,它应该是$!bar$.bar。我明白了。

但是为什么这不会死

更详细地看一下,这里的问题似乎是我试图在$! 上调用一个(不存在的)方法bar,此时它是Nil,因为没有没有任何错误。

看起来我实际上可以在Nil 上调用我想要的任何方法,它们都默默地返回Nil,包括Nil.this-is-a-fake-methodNil.reverse-entropy(123) 之类的东西。

这是一个功能吗?如果有,原因是什么?

【问题讨论】:

    标签: raku


    【解决方案1】:

    这个问题(以及霍布斯的回答)也让我感到……不安:我最终找到了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
    

    ((=:=之间的区别在这里介绍:https://docs.raku.org/language/containers#Binding))

    ...所以一般的想法是,“缺失值或良性故障”在常规代码中远没有我(也许你也是?)突然担心的那么普遍:然而,当你打算使用正则表达式匹配直接,并在与直接调用$! 上的方法相关的特定意外情况下工作。

    这让我更加了解NilAny 之间的区别,并且提供的理由对我来说更有意义。

    【讨论】:

    • Nil 将容器设置为其默认状态。您可以更改默认值。 my $foo is default(42) = 5;$foo = Nil;say $foo; # 42
    【解决方案2】:

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

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

    say Nil.ITotallyJustMadeThisUp;  # OUTPUT: «Nil␤» 
    say (Nil)[100];                  # OUTPUT: «Nil␤» 
    say (Nil){100};                  # OUTPUT: «Nil␤»
    

    Synopsis 2 声明“Nil 上的任何未定义方法调用都会返回Nil,因此Nil 会向下传播方法调用链。同样地,Nil 上的任何下标操作都会返回Nil”,因此意图似乎允许像$foo.Bar()[0].Baz() 这样的表达式,而不需要在每一步检查Nil,或者特殊的“Nil-safe”方法调用和下标运算符。

    【讨论】:

    • 确实如此。很久以前也是如此:github.com/rakudo/rakudo/commit/174727377f(2013 年 12 月)另见相关猜测:design.raku.org/S02.html#Nil
    • @ElizabethMattijsen 啊,我认为 S02 有答案。 “Nil 上的任何未定义方法调用都会返回Nil,因此Nil 会向下传播方法调用链。”因此,您可以执行 $foo.Bar().Baz().Blah() 而无需在每一步都进行 nil 测试或特殊的 ?. 类型的运算符(只要您最后正确处理 nil )。我会编辑的,谢谢。
    • A Nil 不会出错,只会返回更多 Nil 在 Obj-C 和以类似方式使用的 NS 框架中得到相当广泛的使用——允许链式调用继续传递零。我不知道异常和捕获它们的确切性能损失,但我的猜测是Nil 链接可以更有效,如果不那么灵活。
    • (但这是一个完全不知情的猜测,所以我很高兴 lizmat 或 jnthn 告诉我我错了,我需要闭嘴 :-))
    • Nil 类有一个FALLBACK docs.raku.org/language/typesystem#index-entry-FALLBACK_(method) 方法,它返回Nil。基本上,就在由于找不到方法而引发异常之前,会检查FALLBACK,并在可用时调用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-20
    • 1970-01-01
    • 2010-09-14
    • 2021-03-20
    相关资源
    最近更新 更多