对于集合和序列,在它们上调用str
时,Clojure会返回它们作为字符串的EDN-like
表示形式,这与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-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-seq
或反复在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中似乎也是如此。