是否可以使用Clojure的case表单与Java枚举? [英] Is it possible to use Clojure's case form with a Java enum?

查看:220
本文介绍了是否可以使用Clojure的case表单与Java枚举?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

案例 doc说


与cond和condp不同,case恒定时间分派...所有方式的常数
表达式都是可以接受的。

Unlike cond and condp, case does a constant-time dispatch... All manner of constant expressions are acceptable in case.

case 的常量分派以匹配Java枚举。 Java的 switch 语句适用于枚举,但在Clojure中执行以下操作:

I would like to benefit from case's constant-time dispatch to match on Java enums. Java's switch statement works well with enums, but doing the following in Clojure:

(defn foo [x] 
   (case x 
      java.util.concurrent.TimeUnit/MILLISECONDS "yes!"))

(foo java.util.concurrent.TimeUnit/MILLISECONDS)

结果: IllegalArgumentException没有匹配的子句:MILLISECONDS

Results in: IllegalArgumentException No matching clause: MILLISECONDS

case 中是否不支持枚举?我做错了什么?我必须诉诸 cond 还是有更好的解决方案?

Are enums not supported in case? Am I doing something wrong? Must I resort to cond or is there a better solution?

推荐答案

这里的问题是 case 的测试常量,如文档中所述,必须是编译时文字。所以,不是解析 java.util.concurrent.TimeUnit / MILLISECONDS ,文字符号'java.util.concurrent.TimeUnit / MILLISECONDS 正在测试。

The problem here is that case's test constants, as described in the docs, " must be compile-time literals". So, rather than resolving java.util.concurrent.TimeUnit/MILLISECONDS, the literal symbol 'java.util.concurrent.TimeUnit/MILLISECONDS is being tested against.

(foo java.util.concurrent.TimeUnit/MILLISECONDS) ; IllegalArgumentException
(foo 'java.util.concurrent.TimeUnit/MILLISECONDS) ; yes!

相反,解决方案是在 .ordinal Enum 实例,这是Java本身在编译 switch 语句时枚举:

Instead, the solution is to dispatch on the .ordinal of the Enum instance, which is what Java itself does when compiling switch statements over enums:

(defn foo [x]
  (case (.ordinal x)
    2 "yes!"))

您可以将此模式包装在正确评估用例序号的宏中:

You can wrap this pattern in a macro which correctly evaluates the case ordinals for you:

(defmacro case-enum
  "Like `case`, but explicitly dispatch on Java enum ordinals."
  [e & clauses]
  (letfn [(enum-ordinal [e] `(let [^Enum e# ~e] (.ordinal e#)))]
    `(case ~(enum-ordinal e)
       ~@(concat
          (mapcat (fn [[test result]]
                    [(eval (enum-ordinal test)) result])
                  (partition 2 clauses))
          (when (odd? (count clauses))
            (list (last clauses)))))))

这篇关于是否可以使用Clojure的case表单与Java枚举?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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