7

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

(first alist)

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

4

4 回答 4

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)
于 2013-02-09T22:24:41.457 回答
5

这将在一个包含除一个元素之外的任何元素的集合上爆炸。在惰性序列上也能正常工作。

(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")))))
于 2013-02-13T10:34:18.367 回答
1

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

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

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

也就是说,在您的情况下,我可能会写如下内容:

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

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

于 2013-02-09T21:13:32.077 回答
0

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

于 2017-08-08T21:42:00.203 回答