Clojure case 语句与类 [英] Clojure case statement with classes
问题描述
我想打开给定对象的类以对其进行编码.
(defn encoding-msg-for [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)零~"))
当我调用(encoded-msg-for {})
时,它返回No matching子句:class clojure.lang.PersistentArrayMap
奇怪的是,将案例放入哈希映射(类作为键和字符串作为值)非常有效.
另外,(= (class {}) clojure.lang.PersistentArrayMap)
为真.这里发生了什么比较,我如何切换对象本身的类或(更好)其层次结构中的某些内容?
我相信 case
将类名视为文字符号 - 它不会将它们解析为实际的类:
这相当不直观,但它适用于 Clojure 的 case
.无论如何,惯用的方法是使用 defmulti
和 defmethod
而不是打开 type
:
(定义多重编码的味精类)(defmethod 编码-msg java.util.Map [x] 5)(defmethod 编码-msg java.lang.Double [x] 7)>>>(编码-味精{})5>>>(编码味精 2.0)7
调度程序使用 isa?
谓词,它可以很好地处理类型的比较,特别是它与 Java 继承配合得很好.
如果您不想使用 defmulti
,那么 condp
可能会替换您的用例中的 case
,因为它会正确评估测试-表达式.另一方面,它不提供恒定时间调度.
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 "~"
)
)
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.
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?
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
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
The dispatcher uses the isa?
predicate which deals well with the comparisons of types, in particular it works well with Java inheritance.
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 case 语句与类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!