Clojure seq作为Scala Option[T]的替代品



Scala提供了Option[T], Some[T] extends Option[T]None extends Option[Nothing]类的层次结构,我发现它们对于包装可以返回null的Java方法调用非常有用。

val result = Option(someJavaMethodThatReturnsNull())

result的行为类似于0或1项的序列,这取决于Java方法返回的是对象还是nullOptionmap, 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))

这是你想要的吗?

编辑:谨言慎行

如果xnil或为空集合,则(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 `()))

最新更新