这是一场错误的喜剧,我之前基本上完全相反地误解了事情,并且移除了对我的特定问题的所有引用。
我编写了一个自定义的引用类型,实际上并不是 Clojure 的引用类型,而是一种类似的类型。一个含有盒内容的可控制变动的箱子。A 变得有点像原子类型的或 ref。
由于我的类型是一个引用类型,它有一个可变字段,指向引用本身指向的东西,以及其他字段,以便于其他操作。我想使用比较和设置来改变这个可变字段。
在纯 Clojure 中编写,这是通过在 deftype 字段中持有值的原子或 AtomicReference 包装器来完成的。这可行,但增加了 1 或 2 级指针追寻。我想去除这些额外的指针。
Java 为对可变字段直接进行比较和设置提供了至少两种不同的功能(它们可能要求字段为 volatile,我忘记了)。这两种机制都通过创建一种字段访问器对象来实现。典型的类模式似乎是创建字段访问器对象在静态初始化器中,然后在执行 cas 类型字段操作时使用它。
典型的模式不能与当前的deftype一起使用,因为虽然你可以使 deftype 字段可变,但这也使其私有,这使得构建字段访问对象变得困难。你无法从“外部”构建,因为该字段是私有的,并且 deftype 不提供静态初始化的方式。 有解决这个问题的方法,基本上是在你的 deftype 中添加一个什么也不做的函数,只创建并返回字段访问对象,然后在某个顶层静态上下文中构建一个你的 deftype 的空实例并调用该函数。这样是可行的,但感觉相当糟糕。
我最初尝试了创建一个空 deftype 实例,但最终只是编写了一个基本上是 deftype 的极致精简版,用于生成一个有字段和设置 AtomicReferenceFieldUpdater 的静态初始化器的类。这也奏效了,但依赖于对 asm 库的一些经验,以及一些注意事项以使其与 aot 编译良好配合(我认为这部分应该是正确的,但也不敢肯定)。
比较并设置是非常好的,如果能提供某种方法在 deftype 字段上执行比较和设置操作,而不需要我们想要比较和设置的操作的额外对象包裹。在 java/jvm 中有实现这些机制,但在 clojure 中利用它们很痛苦。