case
文档说
与cond和condp不同的是,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
还是有更好的解决方案?
这里的问题是case
的测试常量,如文档中所述,"必须是编译时文字"。因此,不是解析java.util.concurrent.TimeUnit/MILLISECONDS
,而是针对。
'java.util.concurrent.TimeUnit/MILLISECONDS
。(foo java.util.concurrent.TimeUnit/MILLISECONDS) ; IllegalArgumentException
(foo 'java.util.concurrent.TimeUnit/MILLISECONDS) ; yes!
相反,解决方案是在Enum
实例的.ordinal
上调度,这就是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)))))))
您可以在枚举名称上使用use - cond
(case (.name myEnumValue)
"NAME_MY_ENUM" (println "Hey, it works!"))
与其他选项相比,
这里有一个更简单的解决方案,只对情况使用相等性检查-
(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"