2010-07-21 23 views
16

मेरे पास एक जटिल क्लोजर डेटा संरचना है जिसे मैं क्रमबद्ध करना चाहता हूं - मूल रूप से ऑनलाइन गेम के लिए पूरी वर्तमान गेम स्थिति मैं विकसित कर रहा हूं ताकि मैं गेम फ़ाइलों को सहेज सकूं।क्लोजर डेटा स्ट्रक्चर सीरियलाइजेशन

मेरे आवश्यकताएँ हैं:

  • मानव पठनीय पाठ स्वरूप में से कुछ फार्म (मैं शायद पसंद करते हैं इसी क्रम में एस भाव, JSON और एक्सएमएल लेकिन दूसरों के लिए खुला)
  • समर्थन सभी सामान्य Clojure डेटा संरचनाओं, कीवर्ड और पुरातन कस्टम जावा कक्षाएं, defrecords आदि
  • अच्छा प्रदर्शन एक है (यह महत्वपूर्ण है क्योंकि मैं कई मामलों में जावा के readResolve की तरह कुछ करने की ज़रूरत है) के लिए कस्टम क्रमांकन/deserialization कार्यों प्रदान करने के लिए
  • की क्षमता बर्फ से लेकर

कोई अच्छी सिफारिशें? JSON के लिए

+0

क्लोजर के बारे में बहुत कुछ जानने के बिना, क्या क्लोजर से लागू मानक जावा धारावाहिक तंत्र का उपयोग करके यह प्राप्त नहीं किया जा सकता है? – Gian

+0

@Gian - हाँ यह निश्चित रूप से संभव है, लेकिन मैं चीजों को करने का "क्लोजर तरीका" सीखने की कोशिश कर रहा हूं :-) – mikera

+0

आईएमओ क्लोजर तरीका जावा की सुविधाओं का उपयोग करना है जहां वे संबोधित समस्याओं के लिए अच्छे समाधान प्रदान करते हैं। :-) 'सीरियलज़ेबल' डेटा संरचनाओं के अल्पकालिक भंडारण/हस्तांतरण के लिए एक अच्छा समाधान हो सकता है। ऐसा कहकर, मुझे लगता है कि इस उपयोग के मामले में लंबी अवधि के भंडारण के लिए बेहतर प्रारूप उपयुक्त है और यह 'प्रिंट-डुप्ल' द्वारा प्रदान किया जा सकता है। ('Serializable' समस्याएं हो सकती है, अगर कहें, कोर क्लोजर डेटा संरचनाओं को लागू करने वाले वर्गों की संरचना में परिवर्तन होता है;' प्रिंट-डुप्ली 'संभवतः नहीं होगा।) –

उत्तर

11

आप एस-भाव करने के लिए चीजों को क्रमानुसार करने चाहते हैं तो आपके print-dup इस्तेमाल कर सकते हैं:

(binding [*print-dup* true] (println [1 2 3])) 
; prints [1 2 3] 

(defrecord Foo [x]) 
; => user.Foo 
(binding [*print-dup* true] (println (Foo. :foo))) 
; prints #=(user.Foo/create {:x :foo}) 

ध्यान दें कि एक संरचना है, जो रखती है कहते हैं, मुद्रण एक भी वेक्टर के लिए दस संदर्भ इसे पढ़ने वापस के बाद आप देता है दस अलग (identical?) के साथ एक डेटास्ट्रक्चर, हालांकि संरचना के संदर्भ में समतुल्य (=) वैक्टर।

उन मामलों में इसका उपयोग करने के लिए जहां कोई डिफ़ॉल्ट कार्यान्वयन नहीं है, multimethod clojure.core/print-dup लागू करें।

इसके अलावा, Clojure में बहुत कुछ 1.2 java.io.Serializable हैं:

(every? (partial instance? java.io.Serializable) 
     [{1 2} #{"asdf"} :foo 'foo (fn [] :foo)]) 
; => true 

(defrecord Foo []) 
(instance? java.io.Serializable (Foo.)) 
; => true 

ध्यान दें कि आप serializing क्रम-निर्मित fn रों से बचना चाहिए - वे अजीब नाम के साथ एक बंद वर्गों के उदाहरण हैं और आप जीता वैसे भी अपने JVM को पुनरारंभ करने के बाद उन्हें deserialize करने में सक्षम नहीं हैं। एओटी संकलन के साथ, fn एस अपने स्वयं के निश्चित वर्ग नाम प्राप्त करते हैं।

अद्यतन: प्रश्न पर एक टिप्पणी में उल्लेख किया है, Serializable, सबसे अच्छा अल्पकालिक भंडारण/डेटा के हस्तांतरण के लिए अनुकूल है, जबकि print-dup एक लंबी अवधि के भंडारण समाधान (के कई संस्करणों में काम कर रहे के रूप में और अधिक मजबूत होना चाहिए आवेदन, क्लोजर इत्यादि)। इसका कारण यह है कि print-dup धारावाहिक होने वाले वर्गों की संरचना पर निर्भर नहीं है (इसलिए वेक्टर print-dup 'डी आज भी पठनीय होगा जब वेक्टर कार्यान्वयन जावा से क्लोजर के deftype पर स्विच हो जाएगा)।

+0

मुझे लगता है कि 'प्रिंट-डुप्ल' इस उपयोग के मामले के लिए बेहतर समाधान हो सकता है, प्रश्न पर मेरी टिप्पणी देखें ... यदि सहेजने वाले गेम बड़े हो सकते हैं, तो प्रिंटआउट हमेशा संकुचित हो सकते हैं। –

3

आप मानक clojure-contrib.json का उपयोग कर सकते हैं। हालांकि, जैसा कि मुझे याद है, सभी क्लोजर ऑब्जेक्ट्स serializable होना चाहिए ...

+0

यह कोशिश की गई, यह मेरी जावा कक्षाओं को पसंद नहीं करता है: यह फेंकता है उदाहरण के लिए java.lang.Exception: क्लास mikera.persistent.SparseMap के JSON लिखने के बारे में नहीं पता। क्या यह आपके स्वयं के वर्गों के लिए कस्टम धारावाहिक कार्यों को देने का कोई तरीका है? – mikera

+0

यदि कक्षा क्लोजर रिकॉर्ड/प्रकार है तो आप अपनी कक्षा को 'clojure.contrib.json.Write_JSON' इंटरफ़ेस (या प्रोटोकॉल' clojure.contrib.json/Write-JSON' लागू कर सकते हैं) लागू कर सकते हैं। सुनिश्चित नहीं है कि आप उन्हें वापस पढ़ने के बारे में कैसे जाएंगे, हालांकि; मुझे लगता है कि गैर-मानक डेटा संरचनाओं के लिए आप वाईएएमएल जैसे कुछ उपयोग करना चाहते हैं। एक त्वरित Google खोज को 'clj-yaml' http://github.com/lancepantz/clj-yaml एक संभावित समाधान के रूप में पाता है, हालांकि मुझे इस परियोजना के बारे में कुछ भी पता नहीं है। –

+0

आह, बस ध्यान दिया कि 'क्लज-यमल' की रीडमे का कहना है कि यह केवल अब के लिए deserialization का समर्थन करता है ... –

4

यदि सब कुछ क्लोजर डेटा संरचना है, तो यह पहले से ही क्रमबद्ध है (बी 0 सी कोड < -> डेटा)। डिस्क पर डेटा संरचनाओं को बस डंप करें। पुनर्स्थापित करने के लिए, उन्हें वापस लोड करें और (eval)।

+0

आप डिस्क पर कैसे डंप करते हैं? – Zubair

+0

फ़ाइल स्ट्रीम में '* * *' बांधें और '(pr)' का उपयोग करें (और उसके बाद इसे पढ़ने के लिए '(लोड-फ़ाइल)' का उपयोग करें)। एक कार्य उदाहरण के लिए http://groups.google.com/group/clojure/browse_thread/thread/cb5246d07142a3dc?fwc=2&pli=1 देखें। – Greg

+1

उनका मूल्यांकन खतरनाक नहीं है? कोई वहां कुछ कोड छीन सकता है। उन्हें पढ़ना चाहिए लेकिन मूल्यांकन नहीं किया जाना चाहिए। – Pablo

6

edn-format अब क्लोजर के डेटा संरचनाओं का उपयोग करके डेटा स्थानांतरण के लिए मानक के रूप में जारी किया गया है।

क्लोजर डेटा संरचनाओं/मूल्यों को क्रमबद्ध करने के लिए यह एक बहुत अच्छा फिट है - और कई भाषाओं में समर्थित है, इसलिए डेटा इंटरचेंज प्रारूप के रूप में भी उपयोग किया जा सकता है।

+0

यह कोर क्लोजर डेटा संरचनाओं के लिए अच्छी तरह से काम करता है, लेकिन कहें कि आपके पास प्राथमिकता मैप की तरह एक और अधिक विदेशी डेटा संरचना थी (जो एक पर्सिस्टेंट मैप की तरह दिखती है लेकिन अलग-अलग व्यवहार करती है), तो आपको रीडर मैक्रोज़ या कुछ सही करने की आवश्यकता होगी? – Hendekagon

+0

उनके पास एडन-प्रारूप में यह है: आप यह इंगित करने के लिए मूल्यों को "टैग" कर सकते हैं कि वे एक विशेष प्रकार के हैं और उचित कक्षा बनाने के लिए अपने स्वयं के हैंडलर लिखते हैं। यह सुंदर सेलेवर है! – mikera

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