带有类的 Clojure 案例语句 [英] Clojure case statement with classes
问题描述
我想打开给定对象的类以便对其进行编码.
I want to switch on the class of a given object in order to encode it.
(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
When I call (encoded-msg-for {})
, it returns No matching clause: class clojure.lang.PersistentArrayMap
奇怪的是,将案例放入哈希映射(将类作为键,字符串作为值)效果很好.
What is odd is that putting the cases into a hash-map (with the classes as keys and strings as values) works perfectly well.
另外,(= (class {}) clojure.lang.PersistentArrayMap)
为真.这里发生了什么比较,我如何切换对象本身的类或(更好)其层次结构中的某些东西?
Also, (= (class {}) clojure.lang.PersistentArrayMap)
is true. What comparison is happening here and how can I switch either on the class of the object itself or (better) something in its hierarchy?
推荐答案
我相信 case
将类名视为文字符号 - 它不会将它们解析为实际的类:
I believe case
treats the class names as literal symbols - it does not resolve them to actual classes:
>>> (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
:
This is rather unintuitive, but so it works in Clojure's case
. Anyway, the idiomatic way is to use defmulti
and defmethod
instead of switching on 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 继承.
The dispatcher uses the isa?
predicate which deals well with the comparisons of types, in particular it works well with Java inheritance.
如果您不想使用 defmulti
,则 condp
可能会在您的用例中替换 case
,因为它会正确评估测试-表达式.另一方面,它不提供恒定的时间调度.
If you don't want to use defmulti
, then condp
might replace case
in your use case, as it properly evaluates the test-expressions. On the other hand it doesn't provide constant time dispatch.
这篇关于带有类的 Clojure 案例语句的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!