使用Clojure,假设t
代表一个Java对象,我有一个[ts]
的集合。
如何将.setter
映射到[ts]
?我在使用(map #(.setter %1 %2) ts [vals])
时遇到问题。当我之后访问相关的getter时,我会返回nil
s的列表。
答案 0 :(得分:2)
听起来setter
方法没有返回修改后的t
对象。如果你写了setter
,你可以修改它,或者你只需要保留原来的ts
(但也要确保使用dorun
来挤出懒惰map
):
(let [ts ...]
(dorun (map #(.setter %1 %2) ts [vals]))
(println "Modified ts:" ts))
另一种选择,如果让map
返回集合会更方便,就是这样做:
(dorun (map #(do (.setter %1 %2) %1) ts [vals]))
答案 1 :(得分:2)
作为ArrayList
Java类的示例。我创建了其中的三个,然后我添加" s1"到第一个," s2"到第二个" s3"到第三个。这是我的" setter"。
然后我读了每个的第一个值,我希望得到" s1"," s2"," s3" - 这个例子中的吸气剂。
(let [ts [(java.util.ArrayList. 1)
(java.util.ArrayList. 1)
(java.util.ArrayList. 1)]]
; Add one element to each of the ArrayList's
(doall (map #(.add %1 %2) ts ["s1" "s2" "s3"]))
; Verify that elements are indeed added.
(doall (map #(.get %1 0) ts)))
此示例按预期工作 - 后者mapv
返回("s1" "s2" "s3")
。
为什么类似的方法对你不起作用?好吧,我强烈怀疑是因为你使用了map
来返回一个懒惰的序列。
map
返回一个惰性序列,这意味着除非您尝试获取/使用由它生成的值,否则它不会进行评估 - 并且您通常不需要来自setter的返回值。这意味着永远不会调用你的setter。
这就是我使用doall
的原因 - 它将采用一个懒惰的序列并实现它,这意味着每个元素都将被计算(在你的情况下 - 每个setter都会被调用)。
我的例子,当我在设置元素时仅使用map
而不是doall
时,会失败:
(let [ts [(java.util.ArrayList. 1)
(java.util.ArrayList. 1)
(java.util.ArrayList. 1)]]
; Use a lazy map here - without doall
(map #(.add %1 %2) ts ["s1" "s2" "s3"])
(doall (map #(.get %1 0) ts)))
; java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
确实失败了,因为没有添加任何元素。
或者,您可以使用返回向量的mapv
变体,因此始终不是懒惰的:
(let [ts [(java.util.ArrayList. 1)
(java.util.ArrayList. 1)
(java.util.ArrayList. 1)]]
; Use a lazy map, but realize sequence using doall
(doall (map #(.add %1 %2) ts ["s1" "s2" "s3"]))
(mapv #(.get %1 0) ts))
正如@John Wiseman在评论中指出的那样,mapv
可能是一个更糟糕的选择,因为它并不总是很清楚,它曾用于强迫实现,而{{1}明确而明显。
关于懒惰序列的一句话:
doall
了解懒惰seqs是一件好事,因为它们是Clojure代码库中使用的强大工具。他们带来的一个反直觉的东西是创造无限序列的能力,即(范围)创建从0开始的所有数字的无限序列。所以它完全合法:
A lazy seq is a seq whose members aren't computed until you try to access them.
它将创建所有数字的无限懒惰的正方形序列!