在Clojure中使用gen-class声明成员变量

时间:2009-10-18 05:03:19

标签: clojure

我正在学习如何在Clojure中扩展Java类,但我没有看到声明新成员变量的方法;我只看到了一种方法。

(ns test.aclass
  (:gen-class
    :methods [[foo [] String]]))

是否有:members关键字或其他声明成员变量的方式?

3 个答案:

答案 0 :(得分:5)

:state name

如果提供,将创建具有给定名称的公共最终实例字段。您必须提供:init函数才能为状态提供值。请注意,尽管是final,但状态可以是ref或agent,支持使用事务或异步变异语义创建Java对象。

website上有一个如何使用它的例子。

答案 1 :(得分:1)

我也遇到了一些麻烦。下面的例子并不优雅,但是在Clojure而不是Java中编写愚蠢的小胶水类非常简单。请注意,我为线程安全所做的就是确保字段更新是原子的 - 我没有做任何其他并发操作,这可能会产生真正的不同。

init方法为对象创建实例变量。 setfieldgetfield宏缩写了原子更新的簿记。

(ns  #^{:doc "A simple class with instance vars"
    :author "David G. Durand"}
   com.tizra.example )

(gen-class
  :name com.tizra.example.Demo
  :state state
  :init init
  :prefix "-"
  :main false
  :methods [[setLocation [String] void]
            [getLocation [] String]]
)

(defn -init []
  "store our fields as a hash"
  [[] (atom {:location "default"})])

(defmacro setfield
  [this key value]
  `(swap! (.state ~this) into {~key ~value}))

(defmacro getfield
  [this key]
  `(@(.state ~this) ~key))

(defn -setLocation [this ^java.lang.String loc]
  (setfield this :location loc))

(defn ^String -getLocation
  [this]
  (getfield this :location))

你必须编译它,并确保生成的存根类在你的类路径上,然后你可以像任何其他java类一样创建实例等。

=> (com.tizra.example.Demo.)
#<Demo com.tizra.example.Demo@673a95af>

=> (def ex (com.tizra.example.Demo.))
#'user/ex

=> (.getLocation ex)
"default"

=> (.setLocation ex "time")
nil

=> (.getLocation ex)
"time"

我发现此博客中较长的摘要非常有用:http://kotka.de/blog/2010/02/gen-class_how_it_works_and_how_to_use_it.html

答案 2 :(得分:1)

proxy的主体是一个词法闭包,所以你可以绕过你需要的任何变量。如果,上帝保佑,你需要改变它们,然后绕原子关闭:

(defn lying-list [init-size]
  (let [the-size (atom init-size)]
    (proxy [java.util.ArrayList] []
      (size [] @the-size)
      (remove [idx] (reset! the-size idx), true))))

这里真的不需要实际的Java字段。