如,
(defprotocol P
(foo [x])
(bar [x]))
(extend-protocol P
Superclass ;; a java abstract class
(foo [x]
(println "superclass"))
Subclass ;; a concrete java class implementing the above abstract class
(foo [x]
(foo (cast Superclass x))))
如果致电
(foo subclass-instance)
显然我会得到一个堆栈溢出,但有没有办法完成我在这里尝试做的事情,即调用相同的函数但伪装成通用超类/接口?
更新:一个更清晰的示例,演示了我要问的用例:
(defprotocol P
(extract-properties-into-map [self]))
(extend-protocol P
PropertyContainer ;; abstract class
(extract-properties-into-map
[this]
(into {} (for [[k v] (.getProperties this)] [(keyword k) (read-string v)])))
Foo
(extract-properties-into-map
[this]
(assoc {:properties (extract-properties-into-map
^PropertyContainer this)} ;; this is where it falls apart
:foo-type (.getFooType this)
:foo-permissions (.getPermissions this)
:foo-whatever (.getWhatever this))))
答案 0 :(得分:0)
cast
的问题在于它的作用类似于type assertion
,只是在对象不满足is-a关系的情况下抛出异常。
(defn cast
"Throws a ClassCastException if x is not a c, else returns x."
{:added "1.0"
:static true}
[^Class c x]
(. c (cast x)))
没有新接口被返回到另一个函数中调度,即你有一个堆栈溢出。
我不确定为Interface
扩展协议意味着什么?既然你提供了一个实现,我想你应该首先定义一个type
并在超类型上扩展协议。
答案 1 :(得分:0)
编辑:根据https://gist.github.com/michalmarczyk/1715851
中的delegating-proxy
得出的更好的答案
(defprotocol P
(foo [x])
(bar [x]))
(extend-protocol P
Number ;; a java abstract class
(foo [x]
(println "superclass:" x))
Integer ;; a concrete java class implementing the above abstract class
(foo [x]
(foo (delegating-proxy x [Number] []))))
用
调用(foo (Integer. 1))
=> superclass: 1
虽然它问了问题,现在它包裹了原来的x
。根据要求,将foo
委托给协议中未包含的函数可能更好,可能superfoo
(defn superfoo [x] { :byte (.byteValue x) })
(defprotocol P
(foo [x])
(bar [x]))
(extend-protocol P
Number ;; a java abstract class
(foo [x]
(superfoo x))
Integer ;; a concrete java class implementing the above abstract class
(foo [x]
(merge (superfoo x) { :f (.floatValue x)})))
我认为潜在的问题是协议不了解类继承。此外,似乎Clojure应该等待将对象强制转换为类型。在这种情况下,类型提示不起作用。