对于集合和序列,在它们上调用str
时,Clojure将返回它们作为字符串的类似EDN表示,类似于pr-str
的结果。
(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-sEQueNce
上使用时,str
将打印出laZY-sEQueNce
的类型,后跟其实际值的哈希值。
(str (lazy-seq [1 2 3]))
"clojure.lang.LazySeq@7861"
这不仅可以被认为是大多数用例中相当无用的行为(因为大多数人可能更希望它与seq
的字符串化方式相同)。它还强制实现了laZY-sEQueNce
。
(let [ls (map inc [1 2 3])]
(realized? ls))
;;=> false
(let [ls (map inc [1 2 3])]
(str ls)
(realized? ls))
;;=> true
同样,当在eductions
上使用时,str
将首先打印出eductions
的类型,后跟内存位置。
(str (eduction identity [1 2 3]))
"clojure.core.Eduction@2a85e4f4"
与对laZY-sEQueNce
不同,它不会“实现”eductions。
(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-sEQueNce
和eductions的行为似乎是不一致的或错误的。
理想情况下,它会在这两个方面中有所表现
- 变量
str
将导致既不会laZY-sEQueNce
也不会eductions
自行实现,但会将其类型字符串化。这里的想法是,变量str
不会实现“悬而未决的计算”,因此可以在无限的laZY-sEQueNces上或重复应用eductions时安全使用。
- 或者
str
总是会实现“悬而未决的计算”,因此laZY-sEQueNce
和eductions
都将与其他集合和序列以相同的方式字符串化,更类似于对它们调用pr-str
。
备注:在做出决定时考虑这一点,目前ClojureScript的行为不同,它对laZY-sEQueNce进行了第二种选择,我不确定它对eductions做了什么。
cljs.user=> (str (lazy-seq [1 2 3]))
"(1 2 3)"
cljs.user=> (str (eduction identity [1 2 3]))
"[object Object]"
备注2:在外部集合或序列内部嵌套laZY-sEQueNce或eductions时,这种行为似乎也会不同。在这些情况下,它们将被以类似EDN的方式字符串化
(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中也是如此。