4

我想在 Clojure 中创建一个具有属性和方法的对象,我读到 gen-class 和 proxy 可以完成我需要的工作,但它的实现对我来说非常混乱。

我想使用代理来避免 AOT 编译步骤,我阅读了它,但我最好学习如何使用两者中更容易的一个

这是我想在 Clojure 中做的事情

Java代码:

public class MyClass {
    public float myFloat;

    MyClass( float _myFloat ) {
        myFloat = _myFloat
    }

    public void showNumber() {
        println( myFloat );
    }
}

我正在努力使用代理将该代码转换为 Clojure,任何帮助将不胜感激


更新:

显然deftype更适合我的目的,但我仍在努力实现它

这是我的 Clojure 代码:

(deftype Particle [x y]
  Object
  (render [this]
    (no-stroke)
    (fill 200 30 180)
    (ellipse x y 200 200)))

事情是我需要指定一个我不确定要使用哪个协议的协议,所以我正在使用 Object ,因为我正在尝试创建一个类似 java 的对象,但我收到以下错误消息:

无法在接口中定义方法:渲染

如果有帮助,我正在使用 quill,它是 Clojure 的处理端口


更新 2:

好的,我设法获得了一个有效的 defprotocol 和 deftype 组合,但是我还需要学习如何做一件事,那就是向我的类添加成员变量或属性,这是我的 clojure 代码:

(defprotocol ParticleProtocol
  (update [this])
  (render [this]))

(deftype Particle [position]
  ParticleProtocol
  (update [this])
  (render [this]
    (no-stroke)
    (fill 200 30 180)
    (ellipse (.x position) (.y position) 20 20)))

对于这个对象,我想添加几个变量,比如半径等,有什么想法吗?

4

2 回答 2

3

I agree that deftype (or possibly defrecord) is a better than proxy to do this in Clojure, but see my comments at the end to consider all possibilities.

For your question after UPDATE 2.

You can add "properties" to records by specifying them in the arglist:

(deftype Particle [position radius prop3 prop4]
   ...
 )

Remember that types in Clojure are immutable, so there is no concept of setting properties after creating the entity. If some of the properties are optional, it is recommended best practice to create helper "factory" methods, like:

(defn make-particle 
  ([position] (Particle. position nil nil nil))
  ([position radius] (Particle. position radius nil nil))
  ;; etc. add more here as needed
  )

An option to consider is to drop types entirely and just use maps, which have within them whatever "properties/fields" you need. Types are useful when you need to implement abstractions. For your ParticleProtocol - what is the value it is providing? Protocols are meant to provide a way to have polymorphism, so will you have multiple implementations of this protocol?

Chas Emerick did an in depth flowchart of how to choose a data type in Clojure that may help you: http://cemerick.com/2011/07/05/flowchart-for-choosing-the-right-clojure-type-definition-form/


[Update showing example map implementation]:

To construct a map with a "property" and retrieve that property you would do:

(def mymap {:myfloat 3.1415926})
(println "myfloat has value:" (:myfloat mymap))

To provide additional functionality, such as a "render" function, just create a fn that accepts a map with the desired keys:

;; the details are bogus, just showing the syntax
(defn render [m]
  (no-stroke)
  (fill (:radius m) (:position m))
  (do-something-else (:position m)))      

For your update, if you meant to update the values in the particle map, then you need to create a new map, rather than updating an existing one.

(def myparticle {:position 100 :radius 25})

(defn change-pos [particle-map new-pos]
  (assoc-in particle-map [:position] new-pos))

(let [new-particle (change-pos myparticle 300)]
  (println new-particle))
;; prints out {:position 300 :radius 25}
;; orig myparticle still has value {:position 100 :radius 25}

;; or do it directly
(println (assoc myparticle :position 300))
;; prints out {:position 300 :radius 25}
于 2013-03-17T21:50:28.383 回答
1

您可以在 旁边添加“变量” position,如下所示:

(deftype Particle [position radius]
   ...
  )

position and radius aren't really variables, they are more like final attributes. If you need to "vary" them, you should store atoms in them, like this:

(Particle. (atom (Position. 3 4)) (atom 5.0))

But you should really heed the advise of @m0skit0 to stop thinking in terms of objects and classes and start thinking in functions and immutable data structures.

于 2013-03-17T21:46:24.443 回答