Clojure ::获取列表的单个元素,如果列表包含多个元素,则抛出异常

时间:2013-02-09 20:38:46

标签: clojure

我知道在我的代码中的某一点,列表只有一个元素,所以我用

获取它
(first alist)

但是如果列表中有多个元素可以提醒我错误的情况,我也希望代码能够破解。在Clojure中实现这一目标的惯用方法是什么?

4 个答案:

答案 0 :(得分:9)

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 :(得分:4)

这会炸掉一个除了一个元素之外的集合。也适用于懒惰的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")))))

答案 2 :(得分:1)

我无法立即想到一个简洁,惯用的方法来做到这一点。

选项1是没有一个,因为这有点奇怪。如果你知道应该只有一个元素,为什么它首先在列表中?

选项2是有一个,有人会过来告诉他们没有看到它:)

那就是说,在你的情况下,我可能会写一些类似的东西:

(let [[item & rest] alist]
  (if (nil? rest)
    (throw (IllegalArgumentException. "Expected a single-element list"))
    item))

可能更简单,你也可以做(count alist)并确保它只有一个项目。但是,上面的代码具有很好的属性,它不会强制评估超出列表的头部,但取决于您的用例可能不是一个问题。

答案 3 :(得分:0)

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和其他地方找到类似的功能。