对于集合和序列,在调用它们上的str
时,Clojure会返回一个类似于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中也同样适用。