我正在學習如何在Clojure中擴展Java類,但我沒有看到一種方式聲明新的成員變量;我只看到一種方法。用Clojure中的gen-class聲明成員變量
(ns test.aclass
(:gen-class
:methods [[foo [] String]]))
是否有:members
關鍵字或另一種聲明成員變量的方法?
我正在學習如何在Clojure中擴展Java類,但我沒有看到一種方式聲明新的成員變量;我只看到一種方法。用Clojure中的gen-class聲明成員變量
(ns test.aclass
(:gen-class
:methods [[foo [] String]]))
是否有:members
關鍵字或另一種聲明成員變量的方法?
如果提供,具有給定名稱的公共終審場將被建立。您必須提供:init函數才能爲狀態提供值。請注意,雖然最終,狀態可以是參考或代理,從而支持使用事務性或異步變體語義創建Java對象。
在website上有一個關於如何使用它的例子。
我也遇到了一些麻煩。下面的例子並不優雅,但在Clojure而不是Java中編寫愚蠢的小型粘連類非常簡單。注意我爲線程安全所做的一切是確保字段更新是原子的 - 我沒有做任何其他併發的東西,這可能會產生真正的變化。
init方法爲該對象創建實例變量。 setfield
和getfield
宏縮寫原子更新的簿記。
(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))
您必須編譯這一點,並確保所產生的stub類是在classpath中,然後就可以使實例等,就像任何其他的Java類。
=> (com.tizra.example.Demo.)
#<Demo [email protected]>
=> (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
一個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領域。