Clojure case 语句与类 [英] Clojure case statement with classes

查看:21
本文介绍了Clojure case 语句与类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想打开给定对象的类以对其进行编码.

(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 将类名视为文字符号 - 它不会将它们解析为实际的类:

<预><代码>>>>(case 'clojure.lang.PersistentArrayMap clojure.lang.PersistentArrayMap 1 17)1>>>(case clojure.lang.PersistentArrayMap clojure.lang.PersistentArrayMap 1 17)17

这相当不直观,但它适用于 Clojure 的 case.无论如何,惯用的方法是使用 defmultidefmethod 而不是打开 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆