我正在阅读一些Clojure代码,其中有一堆未初始化的值为nil
,用于传递的记录中的数值。
现在有很多Clojure库treat this as idiomatic。这意味着它是一个公认的惯例。
但它也导致NullPointerException
,因为并非所有Clojure核心函数都可以处理nil
作为输入。 (也不应该)。
其他语言具有Maybe
或Option
的概念,以便在值为空时代理值,以减轻NullPointerException
风险。这在Clojure中是可能的 - but not very common。
您可以使用fnil
做一些技巧,但它并不能解决所有问题。
另一种方法是简单地将未初始化的值设置为:empty-value
之类的符号,以强制用户在所有处理代码中显式处理此场景。但这并不是nil
的一个重大提升 - 因为在运行时之前你并没有真正发现所有场景(在其他人的代码中)。
我的问题是:在Clojure中是否有一种惯用的替代方法?
答案 0 :(得分:6)
不确定您是否已经在nil-punning
上阅读了这个lispcast post,但我确实认为这是一个非常好的理由,为什么它是惯用的,涵盖了各种重要的考虑因素,我没有在其他SO问题中看到过提及。
基本上,nil
是clojure中的第一类事物。尽管它具有固有的常规含义,但它是一个适当的值,并且可以在许多上下文中以及依赖于上下文的方式处理。这使得它比宿主语言中的null
更灵活,更强大。
例如,像这样的东西甚至不能在java中编译:
if(null) {
....
}
在clojure中,(if nil ...)
可以正常工作。所以在很多情况下你可以使用nil 安全。我还没有看到一个代码如if(foo != null) { ...
无处不在的 的java代码库。也许java 8' Optional
会改变这种情况。
我认为你可以很容易遇到问题的地方是你正在处理实际null
的java互操作场景。在很多情况下,一个好的clojure包装器库也可以帮助你屏蔽它,并且它有一个很好的理由更喜欢一个而不是直接的java互操作。
鉴于此,您可能需要重新考虑对抗此电流。但既然你在询问替代方案,我认为这很好:prismatic's schema。 Schema有一个Maybe
模式(以及许多其他有用的模式),它在很多场景中运行得非常好。该图书馆非常受欢迎,我已成功使用它。 FWIW,最近在clojure applied书中推荐。
答案 1 :(得分:2)
在Clojure中是否有一种惯用的替代方法?
没有。正如leeor所解释的那样,nil-punning是惯用的。但它并不像Common Lisp那样流行,其中(我被告知)空列表等于nil。
Clojure曾经以这种方式工作,但处理列表的CL函数对应于一般处理序列的Clojure函数。并且这些序列可能是懒惰的,因此将懒惰序列与其他序列统一是非常有用的,因此可以保留任何懒惰。我认为这种演变发生在Clojure 1.2上。 Rich详细描述了here。
如果您想要选项/类型,请查看core.typed库。与Prismatic Schema相比,它在编译时运行。