对于集合和序列,当调用它们上的 str
时,Clojure 将返回类似于 pr-str
结果的字符串形式的它们 EDN-like
表示。
(str (vector 1 2 3))
"[1 2 3]"
(str '(1 2 3))
"(1 2 3)"
(str (seq [1 2 3]))
"(1 2 3)"
(str {:a 1 :b 2})
"{:a 1, :b 2}"
(str #{1 2})
"#{1 2}"
但是当用在 lazy-seq
上时,str
将打印 lazy-seq
的类型,后面跟着其实际值的哈希。
(str (lazy-seq [1 2 3]))
"clojure.lang.LazySeq@7861"
这不仅可能被认为是一种相当无用的行为(因为大多数人可能更希望它像 seq
一样进行字符串化。这也会强制 lazy-seq
实现自己。
(let [ls (map inc [1 2 3])]
(realized? ls))
;;=> false
(let [ls (map inc [1 2 3])]
(str ls)
(realized? ls))
;;=> true
同样,当用于 eduction
时,str
将打印出此时为 eduction
的类型,后面跟随内存位置。
(str (eduction identity [1 2 3]))
"clojure.core.Eduction@2a85e4f4"
与 lazy-seq
不同,它不会“实现”eduction。
(str (eduction (fn[e] (println e) (identity e)) [1 2 3]))
"clojure.core.Eduction@26ae9861"
(str (map (fn[e] (println e) (identity e)) [1 2 3]))
1
2
3
"clojure.lang.LazySeq@7861"
当前对 lazy-seq
和 eduction
的行为似乎要么不一致,要么错误。
理想的做法可能是其中一种
str
将不会导致 lazy-seq
或 eduction
实现自己,但仍然只将它们的类型字符串化。这里的想法是,str
不实现“待定”计算,因此可以安全地用于无限的 lazy-seqs
或重复的 eductions
。
str
将始终实现“待定计算”,因此 lazy-seq
和 eduction
将与其他集合和序列一样进行字符串化,更类似于在它们上调用 pr-str
。
附言:在做出决定时考虑 ClojureScript 当前在 lazy-seq
上行为不同,它选择选项 2,而我不确定它对 eduction
做什么可能是有意义的。
cljs.user=> (str (lazy-seq [1 2 3]))
"(1 2 3)"
cljs.user=> (str (eduction identity [1 2 3]))
"[object Object]"
附言2:似乎当 lazy-seq
或 eduction
被嵌套在其他集合或序列中时,它们在这些情况下的行为也不同,即在这些情况下,它们将以 EDN-like
的方式字符串化
(str [1 (map identity [2 3]) 4])
"[1 (2 3) 4]"
(str (seq [1 (map identity [2 3]) 4]))
"(1 (2 3) 4)"
(str [1 (eduction identity [2 3]) 4])
"[1 (2 3) 4]"
(str (seq [1 (eduction identity [2 3]) 4]))
"(1 (2 3) 4)"
这在 ClojureScript 中似乎也是这种情况。