Scala提供了Option[T]
, Some[T] extends Option[T]
和None extends Option[Nothing]
类的层次结构,我发现它们对于包装可以返回null
的Java方法调用非常有用。
val result = Option(someJavaMethodThatReturnsNull())
result
的行为类似于0或1项的序列,这取决于Java方法返回的是对象还是null
。Option
有map
, filter
等方法,你可以像使用序列一样使用它们,如果原始序列是Some[T]
,则返回新序列(Some
),如果原始序列是None
,则返回None
。
看起来Clojure函数seq
的行为类似:如果x非空,(seq x)
将是一个项目的序列,如果x为空,nil
将是一个项目的序列。这个值可以传递给(map ...)
、(filter ...)
等,就像Scala的Option
方法一样。
我错过了什么吗?这种模式有意义吗?对于经验丰富的Clojure程序员来说,这是一个"尤里卡!"的时刻吗?
你总是可以使用maybe单子,这是接近scala选项(和haskell maybe)当然没有静态类型安全。
还有家庭的?线程函数(.?是Java互操作的更好选择)
当然可以使用Clojure序列来表示零个、一个或多个返回值。
如果你的函数实际上期望返回一个集合,这是一个明智的方法,也是非常惯用的方法。
然而,我不建议使用序列来模拟选项类型。这可能会使API的用户感到困惑。在Clojure中,正常和习惯的方法是,如果一个值不可用则返回nil,如果可用则直接返回该值。
比较:
(if-let [a (function-that-returns-nil-or-result)]
(do-something-with a))
如果您使用序列来模拟选项类型,则需要:
(if-let [a (function-that-returns-a-possibly-empty-sequence)]
(do-something-with (first a)))
我肯定更喜欢第一个选项....为什么我们需要或者希望API用户使用first
来解包序列的结果?
一般来说,nil在Clojure中工作得很好(比其他语言好得多),因为:
- 所有的库函数都将nil解释为空序列,所以你不太可能遇到NullPointerExceptions。
- nil也被认为是"假",因此可以方便地用于布尔运算。
No。如果集合非空,seq
将返回一个抽象的、顺序的视图。否则nil
。所以它和你想要的完全无关。但是,您可以在if测试中使用nil
。如:
(when-let [thing (.someMethodThatReturnsSomethingOrNil other-thing)]
(run-only-when thing is-not-nil-or-false))
这是你想要的吗?
编辑:谨言慎行
如果x
为nil
或为空集合,则(seq x)
将返回nil
。然而,map
, filter
等将接受nil
作为它们的集合参数(即,它们不会中断)并返回一个空序列。这可能会给出您期望从Scala的Option
语句中得到的结果。
下列语句将返回一个空序列:
(map (fn [x] x) (seq nil))
(map (fn [x] x) (seq `()))
(filter even? (seq nil))
(filter even? (seq `()))