2013-05-27 26 views
10

Các case doc nóiCó thể sử dụng biểu mẫu trường hợp của Clojure với Java enum không?

Không giống như cond và condp, trường hợp không có văn bản liên tục theo thời gian ... Tất cả các cách thức của hằng số biểu thức được chấp nhận trong trường hợp.

Tôi muốn hưởng lợi từ việc gửi liên tục trong thời gian case để khớp với các enums Java. tuyên bố switch Java hoạt động tốt với sự đếm, nhưng làm như sau trong Clojure:

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

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

Kết quả trong: IllegalArgumentException No matching clause: MILLISECONDS

đang enums không được hỗ trợ trong case? Tôi có làm điều gì sai? Tôi có phải sử dụng cond hoặc có giải pháp tốt hơn không?

Trả lời

6

Vấn đề ở đây là hằng số kiểm tra của case, như được mô tả trong tài liệu ", phải là thời gian biên dịch literals". Vì vậy, thay vì giải quyết java.util.concurrent.TimeUnit/MILLISECONDS, biểu tượng chữ 'java.util.concurrent.TimeUnit/MILLISECONDS đang được thử nghiệm.

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

Thay vào đó, giải pháp là để gửi về .ordinal của Enum dụ, đó là những gì Java chính nó khi biên dịch switch báo cáo trên enums:

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

Bạn có thể quấn mô hình này trong một macro đánh giá chính xác các trường hợp cho bạn:

(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) 
     [email protected](concat 
      (mapcat (fn [[test result]] 
        [(eval (enum-ordinal test)) result]) 
        (partition 2 clauses)) 
      (when (odd? (count clauses)) 
      (list (last clauses))))))) 
+3

cemerick có ghi-up và cách giải quyết cho điều này tại http://cemerick.com/2010/08/03/enhancing-clojures-case-to-evaluate-dispatch-values/ –

+0

Cảm ơn, cả hai bạn! Cả hai giải pháp thứ tự (tôi đang sử dụng này trong một macro để dễ đọc không phải là một vấn đề) và giải pháp của cemerick làm việc tốt. – pron

+0

Tôi đã quá phát ban: rõ ràng là trường hợp của cemerick + không hoạt động cho enums: '(case + java.util.concurrent.TimeUnit/MINUTES java.util.concurrent.TimeUnit/MINUTES" yes! "); CompilerException java.lang.RuntimeException: Không thể nhúng đối tượng trong mã'. (nhưng các giải pháp thứ tự hiện, rõ ràng) – pron

3

Bạn có thể sử dụng lệnh cho tên của enumm

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

Dường như với tôi rất đơn giản so với các lựa chọn thay thế

+0

Câu trả lời này phải là câu trả lời được chấp nhận. Nó duy trì hiệu suất thời gian không đổi của 'case' và duy trì ngữ nghĩa của' Enum'. Nó mất kiểm tra thời gian biên dịch cho 'Enum', nhưng kiểm tra thời gian biên dịch thường được giao dịch trong Clojure cho các lợi ích khác. – Jason

+0

Cảm ơn Jason: D –

0

Dưới đây là một giải pháp đơn giản rằng chỉ cần sử dụng kiểm tra đẳng thức trên các trường hợp -

(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" 
+0

Đó không phải là hoạt động liên tục.Câu hỏi được đặt ra cho một giải pháp liên tục. – pron

Các vấn đề liên quan