Difference between doseq and for in Clojure

Doseq 和 for 在 Clojure 有什么区别?什么时候你会选择使用一个而不是另一个的例子?

28766 次浏览

区别在于,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

如果希望基于其他序列构建新序列,请使用。如果你想根据某些序列的元素来做副作用(打印、写入数据库、发射核弹头等) ,使用 doseq。

还要注意的是,doseq是渴望的,而 for是懒惰的

(for [x [1 2 3]] (println x))

在 REPL 中,这通常会做您想做的事情,但这基本上是一种巧合: REPL 强制 for生成的延迟序列,导致 println 发生。在非交互式环境中,不会打印任何东西。通过比较

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表单返回创建的新变量,而不是绑定到它的值,所以 REPL 没有要打印的内容,而且 lazy将引用一个未实现的惰性 seq: 它的所有元素都没有被计算。eager将参考 nil,它的所有印刷将已完成。