Clojure deftype中的可变字段?

j-g*_*tus 21 clojure deftype

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

但是我不能让这套装置工作.更新字段的语法是什么?或者是否实现了可变性?

(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
Run Code Online (Sandbox Code Playgroud)

使用几天前的1.2快照.

Mic*_*zyk 43

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

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

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

(.getX (Point. 10)) ; still works
(.x (Point. 10))    ; with annotations -- IllegalArgumentException, works without
Run Code Online (Sandbox Code Playgroud)

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

两个选项都在提到(doc deftype); 相关部分如下 - 记住警告!

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

  • 谢谢.你是信息的金矿,很高兴你在这里:) (4认同)