doseq和Clojure之间有什么区别?当你选择使用一个而不是另一个时,有哪些例子?
答案 0 :(得分:153)
不同之处在于for
构建了一个惰性序列并返回它,而doseq
用于执行副作用并返回nil。
user=> (for [x [1 2 3]] (+ x 5))
(6 7 8)
user=> (doseq [x [1 2 3]] (+ x 5))
nil
user=> (doseq [x [1 2 3]] (println x))
1
2
3
nil
如果要基于其他序列构建新序列,请使用for。如果你想根据某些序列中的元素进行副作用(打印,写入数据库,发射核弹头等),请使用doseq。
答案 1 :(得分:56)
另请注意doseq
在for
懒惰时非常渴望。 Rayne回答中缺少的例子是
(for [x [1 2 3]] (println x))
在REPL,这通常会做你想要的,但这基本上是巧合:REPL强制for
产生的延迟序列,导致printlns发生。在非交互式环境中,不会打印任何内容。您可以通过比较
user> (def lazy (for [x [1 2 3]] (println 'lazy x)))
#'user/lazy
user> (def eager (doseq [x [1 2 3]] (println 'eager x)))
eager 1
eager 2
eager 3
#'user/eager
因为def
形式返回创建的新var,而不是绑定到它的值,所以REPL没有打印,lazy
将引用未实现的lazy-seq:它的所有元素都没有计算过。 eager
将引用nil
,并且所有打印都已完成。