Apa perbedaan antara doseq dan untuk di Clojure? Apa saja contoh ketika Anda akan memilih untuk menggunakan salah satu dari yang lain?
Apa perbedaan antara doseq dan untuk di Clojure? Apa saja contoh ketika Anda akan memilih untuk menggunakan salah satu dari yang lain?
Jawaban:
Perbedaannya adalah bahwa for
membangun urutan malas dan mengembalikannya saat doseq
untuk menjalankan efek samping dan mengembalikan nol.
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
Jika Anda ingin membuat urutan baru berdasarkan urutan lain, gunakan untuk. Jika Anda ingin melakukan efek samping (mencetak, menulis ke database, meluncurkan hulu ledak nuklir, dll) berdasarkan elemen dari beberapa urutan, gunakan doseq.
Perhatikan juga yang doseq
bersemangat saat for
sedang malas. Contoh yang hilang dalam jawaban Rayne adalah
(for [x [1 2 3]] (println x))
Di REPL, ini biasanya akan melakukan apa yang Anda inginkan, tetapi itu pada dasarnya kebetulan: REPL memaksa urutan malas yang dihasilkan oleh for
, menyebabkan printlns terjadi. Dalam lingkungan non-interaktif, tidak ada yang akan dicetak. Anda dapat melihat ini beraksi dengan membandingkan hasil
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
Karena def
formulir mengembalikan var baru yang dibuat, dan bukan nilai yang terikat padanya, REPL tidak akan mencetak apa pun, dan lazy
akan merujuk ke lazy-seq yang belum direalisasi: tidak ada elemennya yang telah dihitung sama sekali. eager
akan merujuk ke nil
, dan semua pencetakannya akan selesai.