我想打开给定对象的类以对其进行编码。
(defn encoded-msg-for [msg]
(case (class msg)
java.lang.Double (encode-double msg)
java.lang.String (encode-str msg)
java.lang.Long (encode-int msg)
java.lang.Boolean (encode-bool msg)
clojure.lang.PersistentArrayMap (encode-hash msg)
clojure.lang.PersistentVector (encode-vec msg)
nil "~"
)
)
当我致电(encoded-msg-for {})
时,会返回No matching clause: class clojure.lang.PersistentArrayMap
奇怪的是,将案例放入哈希映射(将类作为键和字符串作为值)非常有效。
此外,(= (class {}) clojure.lang.PersistentArrayMap)
是真的。在这里进行了什么比较,我如何切换对象本身的类或(更好)在其层次结构中的某些东西?
答案 0 :(得分:14)
我相信case
将类名视为文字符号 - 它不会将它们解析为实际的类:
>>> (case 'clojure.lang.PersistentArrayMap clojure.lang.PersistentArrayMap 1 17)
1
>>> (case clojure.lang.PersistentArrayMap clojure.lang.PersistentArrayMap 1 17)
17
这是非常不直观的,但它适用于Clojure的case
。无论如何,惯用的方法是使用defmulti
和defmethod
而不是开启type
:
(defmulti encoded-msg class)
(defmethod encoded-msg java.util.Map [x] 5)
(defmethod encoded-msg java.lang.Double [x] 7)
>>> (encoded-msg {})
5
>>> (encoded-msg 2.0)
7
调度程序使用isa?
谓词,它可以很好地处理类型的比较,特别是它适用于Java继承。
如果您不想使用defmulti
,那么condp
可能会在您的用例中替换case
,因为它会正确评估测试表达式。另一方面,它没有提供恒定的时间调度。
答案 1 :(得分:8)
如果您只在课堂上发送,那么protocols可能是一个很好的解决方案,因为它们将使您(或您的API的客户端)能够在以后为其他类型提供实施,这里是一个例子:
(defprotocol Encodable
(encode [this]))
(extend-protocol Encodable
java.lang.String
(encode [this] (println "encoding string"))
clojure.lang.PersistentVector
(encode [this] (println "encoding vector")))
如果您需要进行更精细的调度,或者您知道不需要扩展到其他类型,那么此解决方案可能会有太多样板。
答案 2 :(得分:3)
如果您正在寻找另一种方法来实现这一目标,请查看X <- array(rnorm(672), c(4, 7, 12, 2))
V <- matrix(rnorm(132), 12, 11) # p1 = 2, p2 = 3, V is of dimension D x D-1
d <- dim(X)
X.out <- array(0, dim=c(d[1:2], d[3]-1, d[4]))
for(i in 1:d[1]){
for (j in 1:d[4]){
X.out[i,,,j] <- X[i,,,j]%*%V # p1 = 2, p2 = 3
}
}
:
condp