我已经习惯了python/java中的OO.现在做Clojure.我遇到了defrecord,但似乎我必须为我希望记录实现的每个函数或函数集定义一个协议.创建新协议会产生摩擦.我不仅要说出我想要的功能,还要说出协议.我正在寻找的是一种"很好地"将函数与记录相关联的方法,以便函数可以通过this参数访问记录的参数,而无需定义新协议或向现有协议添加函数.
Ale*_*ler 21
如果你还没有尝试多方法的是,他们可能更接近你在找什么.
限定:
(defrecord Person [first middle last])
(defmulti get-name class)
(defmethod get-name Person [person] (:first person))
Run Code Online (Sandbox Code Playgroud)
使用:
(def captain (Person. "James" "T" "Kirk"))
(get-name captain)
Run Code Online (Sandbox Code Playgroud)
选择的多方法实现基于defmulti中的dispatch函数(一个将args传递给函数并返回调度值的函数).通常"class"是调度函数,就像这里一样,调度类型.Multimethods支持多个独立的ad-hoc或基于Java的类型层次结构,默认实现等.
但总的来说,我想也许你可能想退一步考虑一下你是否真的需要协议或多方法.你似乎试图在Clojure中"做OO".虽然OO(如多态)的各个方面都很棒,但也许您应该尝试以其他方式思考您的问题.例如,在我刚刚给出的示例中,没有令人信服的理由(尚未)以多态方式实现get-name.为什么不说:
(defn get-name [x] (:first x))
Run Code Online (Sandbox Code Playgroud)
你甚至需要个人记录吗?一张简单的地图就够了吗?有时答案是肯定的,有时候没有.
通常,Clojure不提供类继承.如果你真的想要它,你当然可以建立一个等价物(甚至是协议)但通常我发现在Clojure中还有其他更好的方法可以解决这个问题.
mik*_*era 14
好问题.
像往常一样,在Clojure中有一种很好的方法 - 这里是如何在10行Clojure中实现自己的简单动态OO系统(包括继承,多态和封装).
想法:如果需要,您可以将函数放在法线Clojure映射或记录中,从而创建类似OO的结构.然后,您可以以"原型"样式使用它.
; define a prototype instance to serve as your "class"
; use this to define your methods, plus any default values
(def person-class
{:get-full-name
(fn [this] (str (:first-name this) " " (:last-name this)))})
; define an instance by merging member variables into the class
(def john
(merge person-class
{:first-name "John" :last-name "Smith"}))
; macro for calling a method - don't really need it but makes code cleaner
(defmacro call [this method & xs]
`(let [this# ~this] ((~method this#) this# ~@xs)))
; call the "method"
(call john :get-full-name)
=> "John Smith"
; added bonus - inheritance for free!
(def mary (merge john {:first-name "Mary"}))
(call mary :get-full-name)
=> "Mary Smith"
Run Code Online (Sandbox Code Playgroud)