我知道在我的代码中的某个点,一个列表只有一个元素,所以我用
(first alist)
但如果列表有多个元素提醒我错误情况,我也希望代码中断。在 Clojure 中实现这一目标的惯用方法是什么?
我知道在我的代码中的某个点,一个列表只有一个元素,所以我用
(first alist)
但如果列表有多个元素提醒我错误情况,我也希望代码中断。在 Clojure 中实现这一目标的惯用方法是什么?
first
用一个(或其他诗意命名的)函数替换only
为您想要做出断言的前提条件:
(defn only [x] {:pre [(nil? (next x))]} (first x))
(only [1])
=> 1
(only [1 2])
=> AssertionError Assert failed: (nil? (next x)) user/only (NO_SOURCE_FILE:1)
这将在一个包含除一个元素之外的任何元素的集合上爆炸。在惰性序列上也能正常工作。
(defn only
"Gives the sole element of a sequence"
[coll]
(if (seq (rest coll))
(throw (RuntimeException. "should have precisely one item, but had at least 2"))
(if (seq coll)
(first coll)
(throw (RuntimeException. "should have precisely one item, but had 0")))))
我无法立即想到一个简洁、惯用的方法来做到这一点。
选项 1 是没有,因为这有点奇怪。如果您知道应该只有一个元素,为什么它首先在列表中?
选项 2 是有一个,有人会过来告诉你没有看到它:)
也就是说,在您的情况下,我可能会写如下内容:
(let [[item & rest] alist]
(if (nil? rest)
(throw (IllegalArgumentException. "Expected a single-element list"))
item))
可能更简单,您也可以只做(count alist)
并确保它只有一个项目。不过,上面的代码有一个很好的属性,它不会强制评估超出列表的头部,但取决于您的用例,这可能不是问题。
Tupelo 库将此功能定义为核心完整性检查,允许从长度为 1 的向量/列表中“解包”标量值并记录预期结果。定义本身就是简单性:
(defn only
"(only coll)
Ensures that a sequence is of length=1, and returns the only value present.
Throws an exception if the length of the sequence is not one.
Note that, for a length-1 sequence S, (first S), (last S) and (only S) are equivalent."
[coll]
(let [coll-seq (seq coll)
num-items (count coll-seq)]
(when-not (= 1 num-items)
(throw (IllegalArgumentException. (str "only: num-items must=1; num-items=" num-items))))
(clojure.core/first coll-seq)))
您可以在SuchWow 库和其他地方找到类似的功能。