显示缺席

Indicating Absence

我不能在 Stackoverflow 上自作聪明,因为我和他们使用的许可证不兼容。但这并不能阻止我阅读 uzlxxxx 提出的问题。在他最后的知识收获中,他试图用 Nil 来表示链接列表末尾没有值。Nil 是这个博客的老朋友了,我花了很长时间才喜欢上它。

Nil 确实可以表示没有值。表示是一个相当活跃的词,可以问一个问题,谁在向谁表示。我相信 Nil 是在向编译器表示没有值。

my $var = "value";
$var = Nil;
dd $var;
# Any $var = Any

对调试器来说(也就是你和我,调试器不会删除任何错误。我们会删除。),缺失用 Any 表示。正如 jnthn 指出的那样,在链表中的 Node 的情况下,一个与该列表相关联的类型对象更有意义。这不是 Rakudo 正在做的事情。

my constant IterationEnd = nqp::create(Mu);
                           # eqv to Mu.new;

它使用的是 Mu 的实例,这就带来了一些问题。

my $var = Mu.new;
say [$var.Bool, $var.defined];
# OUTPUT: [True True]

请求列表末尾的元素不应该是 True,也不应该是 defined。我们可以通过在其中混入一个角色来解决这个问题。

my \Last = Mu.new but role {
    method defined { False }; 
    method Bool { False }
};
say [.Bool, .defined, .^name] given $var;
# OUTPUT: [False False Mu]

这样更好。它可以和 ifwith// 一起工作。但是对于调试来说,它就不是那么好了。我们不会得到一个特定的错误信息,也不会得到任何未定义的值来自哪里的信息。我们可以用一个更好的名字定义一个单例。

constant \Last = class BeyondLast {
    method defined { False };
    method Bool { False }
}.new but role { method new { die 'Sigleton is better left alone' } };

say [Last.WHAT, Last.defined, Last.so, Last ~~ Last, Last === Last ];
# OUTPUT: [(BeyondLast+{<anon|1>}) False False True True]

现在我们得到了一些未定义的东西,错误的和更好的名字。如果有任何运行时错误,我们不会得到一个消息告诉我们它来自哪里。有一整类的对象是未定义的和错误的。我们可以使用一个装在 Failure 中的异常作为默认值。

constant Last = Failure.new(X::ValueAfterLast.new);
say [Last ~~ Last, Last === Last];
# OUTPUT: [True True]
my $node is default(Last); # line 3
$node = 42;
$node = Nil;
say $node === Last;
say $node;
CATCH { default { say .^name, ': ', .gist } }
# OUTPUT: True
          X::ValueAfterLast: Value after last element requested.
            in block  at /home/dex/tmp/tmp.raku line 3

遗憾的是,默认情况下不允许使用代码对象,否则我们可以得到一个指向 Nil 被分配的堆栈跟踪。如果失败对象滑过,我们至少会得到一个像样的错误信息。

有很多方法来指示异常值。然而,它们都不应该以模块的用户结束。我们得到了 Failure 来解决这个问题。

by glfdex.

comments powered by Disqus