我知道在我的代碼的某一點,一個列表只有一個元素,所以我用的Clojure ::得到一個列表,並拋出異常的單個元素,如果列表中有超過1元
(first alist)
獲得它
但是如果列表中有多個元素來提醒我錯誤的情況,我還想讓代碼打破。在Clojure中實現這一點的慣用方法是什麼?
我知道在我的代碼的某一點,一個列表只有一個元素,所以我用的Clojure ::得到一個列表,並拋出異常的單個元素,如果列表中有超過1元
(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)
我不能立即想到一個很好的簡潔,慣用的方式來做到這一點。
選項1是沒有一個,因爲這是一個奇怪的情況。如果你知道應該只有一個元素,爲什麼它首先在列表中?
選項2的是,有一次,有人會來告訴關閉沒有看到它:)
這就是說,在你的情況我可能會寫類似:
(let [[item & rest] alist]
(if (nil? rest)
(throw (IllegalArgumentException. "Expected a single-element list"))
item))
可能更簡單一點,您也可以只做(count alist)
並確保它只有一個項目。但是,上面的代碼具有很好的屬性,它不會強制評估超出列表的頭部,但取決於您可能不需要擔心的用例。
我不喜歡'count'方法,因爲它不適用於長序列或無限序列。 – 2013-12-15 12:24:30
這將炸燬對集合比一個元素其他任何東西。懶惰的seqs也能很好地工作。
(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 - 這是一個很好的答案,因爲除了避免使用'count',它可以同時處理''(僅nil)'和'(only(sorted-map 1:a 2:b))''。 – 2017-04-13 02:34:48
The Tupelo library具有被定義爲芯完整性檢查此功能,允許人們從長度爲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 library和其他地方類似的功能。
是的。這個答案。 – dfreeman 2013-02-13 22:52:37
'(僅[1 nil])'說明了此解決方案中的一個錯誤。 – 2013-12-15 12:23:54
@AlexBaranosky謹慎解釋? '(next [1 nil])'是''(nil)'和'(nil?'(nil))'是'false'。因此,'(僅[1 nil])'會根據需要拋出斷言錯誤。 – 2013-12-16 15:15:35