2013-05-27 9 views
10

case दस्तावेज़ कहते हैंक्या जावा एनम के साथ क्लोजर के केस फॉर्म का उपयोग करना संभव है?

cond और condp के विपरीत, मामला एक निरंतर समय प्रेषण करता है ... निरंतर अभिव्यक्ति की सभी प्रकार की आवश्यक मामले में स्वीकार्य हैं।

मैं जावा enums पर मिलान करने के लिए case के स्थिर समय प्रेषण से लाभ उठाना चाहता हूं। जावा के switch बयान enums के साथ अच्छी तरह से काम करता है, लेकिन Clojure में निम्नलिखित कर रही: में

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

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

परिणाम: IllegalArgumentException No matching clause: MILLISECONDS

case में समर्थित नहीं enums रहे हैं? क्या मुझसे कुछ गलत हो रही है? क्या मुझे cond का सहारा लेना चाहिए या क्या कोई बेहतर समाधान है?

उत्तर

6

यहां समस्या यह है कि दस्तावेज़ों में वर्णित case के टेस्ट स्थिरांक, "संकलित समय अक्षर होना चाहिए"। तो, java.util.concurrent.TimeUnit/MILLISECONDS को हल करने के बजाय, शाब्दिक प्रतीक 'java.util.concurrent.TimeUnit/MILLISECONDS का परीक्षण किया जा रहा है। आप किसी मैक्रो में इस पैटर्न लपेट कर सकते हैं

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

:

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

इसके बजाय, समाधान Enum उदाहरण है, जो है क्या जावा ही जब enums से अधिक switch बयान संकलन करता है .ordinal पर प्रेषण करने के लिए है जो आपके लिए केस ordinals का सही मूल्यांकन करता है:

(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 एक लेख और के लिए वैकल्पिक हल है यह http://cemerick.com/2010/08/03/enhancing-clojures-case-to-evaluate-dispatch-values/ –

+0

धन्यवाद, आप दोनों! दोनों औपचारिक समाधान (मैं इसे मैक्रो में उपयोग कर रहा हूं इसलिए पठनीयता एक मुद्दा नहीं है) और सेमेरिक का समाधान अच्छी तरह से काम करता है। – pron

+0

मैं बहुत परेशान था: स्पष्ट रूप से cemerick का मामला + enums के लिए काम नहीं करता है: '(मामला + java.util.concurrent.TimeUnit/MINUTES java.util.concurrent.TimeUnit/MINUTES" हाँ! "); CompilerException java.lang.RuntimeException: ऑब्जेक्ट को कोड में एम्बेड नहीं किया जा सकता है। (लेकिन औपचारिक समाधान स्पष्ट रूप से करता है) – pron

3

आप एनम के नाम पर एक कंड का उपयोग कर सकते हैं

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

विकल्पों की तुलना में बहुत ही सरल मुझे लगता है

+0

यह उत्तर स्वीकार्य उत्तर होना चाहिए। यह 'केस' के निरंतर समय के प्रदर्शन को बनाए रखता है और 'एनम' के अर्थशास्त्र को संरक्षित करता है। यह 'एनम' के लिए संकलन समय की जांच खो देता है, लेकिन संकलन समय चेक आमतौर पर अन्य लाभों के लिए क्लोजर में कारोबार किया जाता है। – Jason

+0

धन्यवाद जेसन: डी –

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

यह निरंतर समय ऑपरेशन नहीं है।सवाल निरंतर समय समाधान के लिए कहा। – pron

संबंधित मुद्दे