对于集合和序列,当在它们上调用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-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
或重复的eduction
上安全使用。
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样式进行字符串化。
(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中也适用。