10

医生case

与 cond 和 condp 不同,case 会进行恒定时间调度……所有形式的常量表达式在 case 中都是可以接受的。

我想从case的恒定时间调度中受益,以匹配 Java 枚举。Java 的switch语句适用于枚举,但在 Clojure 中执行以下操作:

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

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

结果是:IllegalArgumentException No matching clause: MILLISECONDS

不支持枚举case吗?难道我做错了什么?我必须求助cond还是有更好的解决方案?

4

3 回答 3

7

这里的问题是case's 测试常量,如文档中所述,“必须是编译时文字”。因此,不是解析java.util.concurrent.TimeUnit/MILLISECONDS,而是针对文字符号'java.util.concurrent.TimeUnit/MILLISECONDS进行测试。

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

相反,解决方案是.ordinalEnum实例上调度,这是 Java 本身在switch通过枚举编译语句时所做的:

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

您可以将此模式包装在一个宏中,该宏可以为您正确评估案例序数:

(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)))))))
于 2013-05-27T17:42:50.373 回答
6

您可以在枚举的名称上使用 cond

(case (.name myEnumValue) "NAME_MY_ENUM" (println "Hey, it works!"))

与替代品相比,在我看来非常简单

于 2014-08-09T08:24:40.527 回答
0

这是一个更简单的解决方案,它只对案例使用相等检查 -

(defn cases [v & args]
  (let [clauses (partition 2 2 args)]
    (some #(when (= (first %) v) (second %)) clauses))) 

=> (cases EventType/received EventType/send "A" EventType/received "B")
=> "B"
于 2015-05-20T18:49:43.907 回答