Clojure deftype中的可变字段?

时间:2010-06-28 13:52:43

标签: clojure deftype

我正在尝试使用Clojure 1.2,特别是deftype根据clojure.org documentation支持的可变字段。

但我无法让套装发挥作用。更新字段的语法是什么?或者是否实现了可变性?

(definterface IPoint
  (getX [])
  (setX [v]))

(deftype Point [x]
  IPoint
  (getX [this] x)
  (setX [this v] (set! (.x this) v)))

user=> (def p (Point. 10))
user=> (.getX p)
10
user=> (.setX p 20)
ClassCastException: user.Point cannot be cast to compile__stub.user.Point

使用几天前的1.2快照。

2 个答案:

答案 0 :(得分:43)

deftype的默认值仍然是字段是不可变的;要覆盖它,您需要使用适当的元数据注释要变为可变的字段的名称。此外,set!实例字段的语法也不同。实现上述工作的示例实现:

(deftype Point [^{:volatile-mutable true} x]
  IPoint
  (getX [_] x)
  (setX [this v] (set! x v)))

还有:unsynchronized-mutable。不同之处在于名称会向有经验的Java开发人员建议。 ;-)请注意,提供任何一个注释都会使该字段成为私有的附加效果,因此不再可能直接访问字段:

(.getX (Point. 10)) ; still works
(.x (Point. 10))    ; with annotations -- IllegalArgumentException, works without

此外,1.2可能支持语法^:volatile-mutable x作为^{:volatile-mutable true} x的简写(这已经在一些新的数字分支上提供)。

(doc deftype)中提到了这两个选项;相关部分如下 - 请注意警告!

  

可以限定字段     元数据:volatile-mutable true或:unsynchronized-mutable     是的,在这个方法中将支持(set!afield aval)     身体。请注意,可变字段非常难以使用     正确地,并且仅用于促进更高层的建设     Clojure中的级别构造,例如Clojure的引用类型     本身。它们仅供专家使用 - 如果语义和     含义:volatile-mutable或:unynchronized-mutable不是     对你来说很明显,你不应该使用它们。

答案 1 :(得分:0)

与Clojure中的大多数事情一样,通过deftype定义的类型的字段是不可变的。尽管您可以使用:volatile-mutable / :unsynchronized-mutable注释来规避这一问题,但这并不普遍。一方面,这样的注释将使该字段私有,因此只有在类型上定义的方法才可以访问(并由此设置)它。但更重要的是,此类构造容易受到数据争夺的影响。

当需要可变性时,idomatic Clojure将使用Clojure的引用类型之一,例如atomref