कंपोजर मार्गों के पीछे "बड़ा विचार" क्या है?


109

मैं क्लजुरे के लिए नया हूं और एक मूल वेब एप्लिकेशन लिखने के लिए कॉम्पोज्योर का उपयोग कर रहा हूं। defroutesहालांकि, मैं कॉम्पोज्योर के सिंटैक्स के साथ एक दीवार मार रहा हूं , और मुझे लगता है कि मुझे यह सब "पीछे" और "क्यों" दोनों को समझने की आवश्यकता है।

ऐसा लगता है जैसे रिंग-स्टाइल एप्लिकेशन HTTP अनुरोध मानचित्र के साथ शुरू होता है, फिर बस मिडलवेयर फ़ंक्शंस की एक श्रृंखला के माध्यम से अनुरोध को पारित करता है जब तक कि यह एक प्रतिक्रिया मानचित्र में परिवर्तित नहीं हो जाता है, जो ब्राउज़र को वापस भेज दिया जाता है। डेवलपर्स के लिए यह शैली बहुत "निम्न स्तर" लगती है, इस प्रकार Compojure जैसे उपकरण की आवश्यकता होती है। मैं अन्य सॉफ्टवेयर पारिस्थितिक तंत्रों में और अधिक सार के लिए इसकी आवश्यकता देख सकता हूं, विशेष रूप से पायथन के डब्ल्यूएसजीआई के साथ।

समस्या यह है कि मैं Compojure के दृष्टिकोण को नहीं समझता। चलो निम्नलिखित defroutesएस-अभिव्यक्ति लेते हैं :

(defroutes main-routes
  (GET "/"  [] (workbench))
  (POST "/save" {form-params :form-params} (str form-params))
  (GET "/test" [& more] (str "<pre>" more "</pre>"))
  (GET ["/:filename" :filename #".*"] [filename]
    (response/file-response filename {:root "./static"}))
  (ANY "*"  [] "<h1>Page not found.</h1>"))

मुझे पता है कि इस सब को समझने की कुंजी कुछ स्थूल वूडू के भीतर है, लेकिन मैं मैक्रोज़ (अभी तक) को पूरी तरह से नहीं समझता। मैं defroutesएक लंबे समय के लिए स्रोत को घूर रहा हूं , लेकिन बस नहीं मिला! यहाँ क्या चल रहा है? "बड़े विचार" को समझने से शायद मुझे इन विशिष्ट प्रश्नों के उत्तर देने में मदद मिलेगी:

  1. मैं एक रूट किए गए फ़ंक्शन (जैसे workbenchफ़ंक्शन) के भीतर से रिंग वातावरण कैसे एक्सेस करूं ? उदाहरण के लिए, कहते हैं कि मैं HTTP_ACCEPT हेडर या अनुरोध के कुछ अन्य भाग / मिडलवेयर का उपयोग करना चाहता था?
  2. विनाशकारी ( {form-params :form-params}) के साथ क्या सौदा है ? विनाश के समय मेरे लिए कौन से कीवर्ड उपलब्ध हैं?

मुझे वास्तव में क्लोजर पसंद है लेकिन मैं बहुत स्टम्प्ड हूं!

जवाबों:


212

कंपोजर समझाया (कुछ हद तक)

एनबी। मैं कॉम्पोज्योर 0.4.1 के साथ काम कर रहा हूं ( यहां GitHub पर 0.4.1 रिलीज कमिट है)।

क्यों?

सबसे ऊपर compojure/core.clj, कॉम्पोज्योर के उद्देश्य का यह सहायक सारांश है:

रिंग संचालकों के निर्माण के लिए एक संक्षिप्त वाक्य रचना।

सतही स्तर पर, यह "सवाल" क्यों है। थोड़ा और गहराई में जाने के लिए, आइए एक नजर डालते हैं कि रिंग-स्टाइल ऐप कैसे कार्य करता है:

  1. एक अनुरोध आता है और रिंग स्पेस के अनुसार क्लोजर मैप में बदल जाता है।

  2. यह नक्शा एक तथाकथित "हैंडलर फ़ंक्शन" में फ़नल है, जिसे एक प्रतिक्रिया (जो कि क्लीजुर मैप भी है) का उत्पादन करने की उम्मीद है।

  3. प्रतिक्रिया मानचित्र वास्तविक HTTP प्रतिक्रिया में बदल जाता है और क्लाइंट को वापस भेज दिया जाता है।

चरण 2. उपरोक्त में सबसे दिलचस्प है, क्योंकि यह अनुरोध में उपयोग किए गए यूआरआई की जांच करने, किसी भी कुकीज़ आदि की जांच करने और अंततः एक उचित प्रतिक्रिया पर पहुंचने की जिम्मेदारी है। स्पष्ट रूप से यह आवश्यक है कि यह सब काम अच्छी तरह से परिभाषित टुकड़ों के संग्रह में निहित हो; ये आम तौर पर एक "बेस" हैंडलर फ़ंक्शन और इसे लपेटने वाले मिडलवेयर फ़ंक्शंस का एक संग्रह है। कॉम्पोजर का उद्देश्य बेस हैंडलर फ़ंक्शन की पीढ़ी को सरल बनाना है।

कैसे?

कॉम्पोज्योर "मार्गों" की धारणा के आसपास बनाया गया है। ये वास्तव में से एक गहरे स्तर पर लागू किया जाता है प्रभाव पुस्तकालय (Compojure परियोजना के एक spinoff - बहुत सी बातें 0.3.x पर अलग पुस्तकालयों में ले जाया गया -> 0.4.x संक्रमण)। एक मार्ग को (1) एक HTTP विधि (GET, PUT, HEAD ...), (2) एक URI पैटर्न (वाक्यविन्यास के साथ निर्दिष्ट जो स्पष्ट रूप से Webby Rubyists से परिचित होगा), (3) एक विनाशकारी रूप में उपयोग किया जाता है। शरीर में उपलब्ध नामों के लिए अनुरोध मानचित्र के कुछ हिस्सों को बाँधना, (4) अभिव्यक्तियों का एक निकाय जो एक वैध रिंग प्रतिक्रिया का उत्पादन करने की आवश्यकता है (गैर-तुच्छ मामलों में यह आमतौर पर एक अलग फ़ंक्शन के लिए केवल एक कॉल है)।

यह एक साधारण उदाहरण पर एक नज़र डालने के लिए एक अच्छा बिंदु हो सकता है:

(def example-route (GET "/" [] "<html>...</html>"))

आइए, REPL में इसका परीक्षण करें (नीचे दिया गया अनुरोध नक्शा न्यूनतम मान्य रिंग अनुरोध मानचित्र है):

user> (example-route {:server-port 80
                      :server-name "127.0.0.1"
                      :remote-addr "127.0.0.1"
                      :uri "/"
                      :scheme :http
                      :headers {}
                      :request-method :get})
{:status 200,
 :headers {"Content-Type" "text/html"},
 :body "<html>...</html>"}

तो :request-methodथे :headबजाय, प्रतिक्रिया होगी nil। हम इस सवाल पर लौटेंगे nilकि यहां एक मिनट में क्या मतलब है (लेकिन ध्यान दें कि यह एक मान्य रिंग प्रतिक्रिया नहीं है!)।

जैसा कि इस उदाहरण से स्पष्ट है, example-routeकेवल एक कार्य है, और उस पर एक बहुत ही सरल; यह, अनुरोध पर लग रहा है निर्धारित करता है कि यह इसके रख-रखाव (परीक्षण करके में रुचि है :request-methodऔर :uri) और, यदि हां, एक बुनियादी प्रतिक्रिया नक्शा प्राप्त होगा।

यह भी स्पष्ट है कि मार्ग के शरीर को वास्तव में उचित प्रतिक्रिया मानचित्र के मूल्यांकन की आवश्यकता नहीं है; कंपोजर स्ट्रिंग्स (जैसा कि ऊपर देखा गया है) और कई अन्य ऑब्जेक्ट प्रकारों के लिए सेंस डिफॉल्ट हैंडलिंग प्रदान करता है; देखने के compojure.response/renderविवरण के लिए multimethod (कोड पूरी तरह से स्वयं का दस्तावेजीकरण यहाँ है)।

आइए defroutesअब प्रयोग करके देखें :

(defroutes example-routes
  (GET "/" [] "get")
  (HEAD "/" [] "head"))

ऊपर दिखाए गए उदाहरण अनुरोध के जवाब और इसके वैरिएंट के साथ :request-method :headउम्मीद की तरह हैं।

आंतरिक कामकाज example-routesऐसे हैं कि प्रत्येक मार्ग को बारी-बारी से करने की कोशिश की जाती है; जैसे ही उनमें से कोई एक गैर- nilप्रतिक्रिया देता है , वह प्रतिक्रिया पूरे example-routesहैंडलर का रिटर्न मान बन जाती है । एक अतिरिक्त सुविधा के रूप में defroutes-Defined हैंडलर अंदर wrap-paramsऔर wrap-cookiesस्पष्ट रूप से लिपटे हुए हैं ।

यहाँ एक और अधिक जटिल मार्ग का उदाहरण दिया गया है:

(def echo-typed-url-route
  (GET "*" {:keys [scheme server-name server-port uri]}
    (str (name scheme) "://" server-name ":" server-port uri)))

पहले इस्तेमाल किए गए खाली वेक्टर के स्थान पर विनाशकारी रूप पर ध्यान दें। यहां मूल विचार यह है कि मार्ग के निकाय को अनुरोध के बारे में कुछ जानकारी में रुचि हो सकती है; चूंकि यह हमेशा एक नक्शे के रूप में आता है, एक साहचर्य विनाशकारी रूप को अनुरोध से जानकारी निकालने और स्थानीय चर में बांधने के लिए आपूर्ति की जा सकती है जो मार्ग के शरीर में गुंजाइश होगी।

उपरोक्त का एक परीक्षण:

user> (echo-typed-url-route {:server-port 80
                             :server-name "127.0.0.1"
                             :remote-addr "127.0.0.1"
                             :uri "/foo/bar"
                             :scheme :http
                             :headers {}
                             :request-method :get})
{:status 200,
 :headers {"Content-Type" "text/html"},
 :body "http://127.0.0.1:80/foo/bar"}

ऊपर दिए गए शानदार अनुवर्ती विचार यह है कि अधिक जटिल मार्ग assocमिलान चरण में अनुरोध पर अतिरिक्त जानकारी दे सकते हैं :

(def echo-first-path-component-route
  (GET "/:fst/*" [fst] fst))

यह एक साथ प्रतिक्रिया :bodyके "foo"पिछले उदाहरण से अनुरोध करने के लिए।

इस नवीनतम उदाहरण के बारे में दो बातें नई हैं: "/:fst/*"गैर-खाली बाध्यकारी वेक्टर [fst]। पहला URI पैटर्न के लिए पूर्वोक्त रेल और सिनात्रा जैसा सिंटैक्स है। यूआरआई सेगमेंट पर रेगेक्स बाधाओं का समर्थन किया गया है (उदाहरण के लिए उपरोक्त में ["/:fst/*" :fst #"[0-9]+"]केवल सभी अंकीय मूल्यों को स्वीकार करने के लिए आपूर्ति की जा सकती है) से ऊपर के उदाहरण से यह स्पष्ट है कि यह थोड़ा अधिक परिष्कृत है :fst। दूसरा :paramsअनुरोध मानचित्र में प्रविष्टि पर मेल खाने का एक सरल तरीका है , जो स्वयं एक मानचित्र है; यह अनुरोध, क्वेरी स्ट्रिंग पैरामीटर और प्रपत्र पैरामीटर से URI सेगमेंट निकालने के लिए उपयोगी है। बाद के बिंदु को स्पष्ट करने के लिए एक उदाहरण:

(defroutes echo-params
  (GET "/" [& more]
    (str more)))

user> (echo-params
       {:server-port 80
        :server-name "127.0.0.1"
        :remote-addr "127.0.0.1"
        :uri "/"
        :query-string "foo=1"
        :scheme :http
        :headers {}
        :request-method :get})
{:status 200,
 :headers {"Content-Type" "text/html"},
 :body "{\"foo\" \"1\"}"}

यह प्रश्न पाठ से उदाहरण पर एक अच्छा समय होगा:

(defroutes main-routes
  (GET "/"  [] (workbench))
  (POST "/save" {form-params :form-params} (str form-params))
  (GET "/test" [& more] (str "<pre>" more "</pre>"))
  (GET ["/:filename" :filename #".*"] [filename]
    (response/file-response filename {:root "./static"}))
  (ANY "*"  [] "<h1>Page not found.</h1>"))

चलो बदले में प्रत्येक मार्ग का विश्लेषण करते हैं:

  1. (GET "/" [] (workbench))- GETअनुरोध के साथ काम करते समय :uri "/", फ़ंक्शन को कॉल करें workbenchऔर जो कुछ भी प्रतिक्रिया मानचित्र में देता है उसे प्रस्तुत करें। (याद रखें कि वापसी मूल्य एक नक्शा हो सकता है, लेकिन यह भी एक स्ट्रिंग आदि)

  2. (POST "/save" {form-params :form-params} (str form-params))- मिडलवेयर :form-paramsद्वारा प्रदान किए गए अनुरोध मानचित्र में एक प्रविष्टि है wrap-params(याद रखें कि यह अंतर्निहित रूप से शामिल है defroutes)। प्रतिक्रिया मानक {:status 200 :headers {"Content-Type" "text/html"} :body ...}के लिए (str form-params)प्रतिस्थापित किया जाएगा ...। (थोड़ा असामान्य POSTहैंडलर, यह ...)

  3. (GET "/test" [& more] (str "<pre> more "</pre>"))- {"foo" "1"}अगर उपयोगकर्ता एजेंट के लिए कहा जाता है, तो यह मानचित्र के स्ट्रिंग प्रतिनिधित्व को प्रतिध्वनित करेगा "/test?foo=1"

  4. (GET ["/:filename" :filename #".*"] [filename] ...)- :filename #".*"भाग कुछ भी नहीं करता है (चूंकि #".*"हमेशा मेल खाता है)। यह ring.util.response/file-responseअपनी प्रतिक्रिया उत्पन्न करने के लिए रिंग यूटिलिटी फ़ंक्शन को कॉल करता है ; {:root "./static"}भाग यह बताता है जहां फ़ाइल देखने के लिए।

  5. (ANY "*" [] ...)- एक कैच-ऑल रूट। यह अच्छा कॉम्पोज्योर अभ्यास है कि इस तरह के मार्ग को defroutesफॉर्म के अंत में हमेशा शामिल करें ताकि यह सुनिश्चित हो सके कि जिस हैंडलर को परिभाषित किया जा रहा है वह हमेशा एक वैध रिंग रिस्पॉन्स मैप (यह याद रखता है कि रूट मिलान विफलता परिणाम है nil)।

इस तरह क्यों?

रिंग मिडलवेयर का एक उद्देश्य अनुरोध मानचित्र में जानकारी जोड़ना है; इस प्रकार कुकी-हैंडलिंग मिडलवेयर :cookiesअनुरोध की एक कुंजी wrap-paramsजोड़ता है , जोड़ता है :query-paramsऔर / या:form-paramsयदि कोई क्वेरी स्ट्रिंग / प्रपत्र डेटा मौजूद है और इसी तरह। (सख्ती से बोलते हुए, सभी सूचनाएँ जो मिडलवेयर फ़ंक्शंस जोड़ रही हैं, उन्हें पहले से ही अनुरोध मानचित्र में मौजूद होना चाहिए, क्योंकि वे जो वे पास कर रही हैं, उनका काम यह है कि वे इसे लपेटने वाले हैंडलर में काम करने के लिए इसे और अधिक सुविधाजनक बनाने के लिए बदल दें।) अंततः "समृद्ध" अनुरोध बेस हैंडलर को दिया जाता है, जो मिडलवेयर द्वारा जोड़े गए सभी अच्छी तरह से प्रीप्रोस्ड जानकारी के साथ अनुरोध मानचित्र की जांच करता है और प्रतिक्रिया उत्पन्न करता है। (मिडलवेयर इससे अधिक जटिल चीजें कर सकता है - जैसे कई "आंतरिक" हैंडलर को लपेटना और उनके बीच चयन करना, यह तय करना कि क्या लपेटे गए हैंडलर को सभी को कॉल करना है आदि, हालांकि, इस उत्तर के दायरे से बाहर है।)

बेस हैंडलर, बदले में, आम तौर पर (गैर-तुच्छ मामलों में) एक फ़ंक्शन है जो अनुरोध के बारे में जानकारी के केवल एक मुट्ठी भर वस्तुओं की आवश्यकता होती है। (जैसे ring.util.response/file-responseअनुरोध के अधिकांश के बारे में परवाह नहीं है; यह केवल एक फ़ाइल नाम की जरूरत है।) इसलिए एक रिंग अनुरोध के प्रासंगिक भागों को निकालने के एक सरल तरीके की आवश्यकता है। कॉम्पोज्योर का उद्देश्य एक विशेष-उद्देश्य पैटर्न मिलान इंजन प्रदान करना है, जैसा कि यह था, जो कि बस यही करता है।


3
"एक अतिरिक्त सुविधा के रूप में, डिफ्राउट-डिफाइंड हैंडलर को रैप-परमेस और रैप-कुकीज में लिपटा जाता है।" - संस्करण 0.6.0 के अनुसार आपको इनको स्पष्ट रूप से जोड़ना होगा। रेफ github.com/weavejester/compojure/commit/…
Dan Midwood

3
बहुत अच्छी तरह से डाल दिया। यह उत्तर कम्पोज्योर के मुखपृष्ठ पर होना चाहिए।
सिद्धार्थ रेड्डी

2
Compojure के लिए किसी भी नए के लिए आवश्यक पढ़ना। मैं इस विषय पर एक लिंक के साथ शुरू किए गए विषय पर हर विकि और ब्लॉग पोस्ट की कामना करता हूं।
डेमॉन

7

जेम्स रीव्स (कॉम्पोज्योर के लेखक) से booleanknot.com पर एक उत्कृष्ट लेख है , और इसे पढ़ने से यह मेरे लिए "क्लिक" हो गया है, इसलिए मैंने इसमें से कुछ को फिर से लिखा है (वास्तव में यही मैंने किया है)।

उसी लेखक के यहाँ एक स्लेडेक भी है , जो इस सटीक प्रश्न का उत्तर देता है।

कॉम्पोज्योर रिंग पर आधारित है , जो http अनुरोधों के लिए एक अमूर्त है।

A concise syntax for generating Ring handlers.

तो, उन रिंग हैंडलर क्या हैं ? डॉक्टर से निकालें:

;; Handlers are functions that define your web application.
;; They take one argument, a map representing a HTTP request,
;; and return a map representing the HTTP response.

;; Let's take a look at an example:

(defn what-is-my-ip [request]
  {:status 200
   :headers {"Content-Type" "text/plain"}
   :body (:remote-addr request)})

बहुत सरल, लेकिन यह भी काफी निम्न स्तर का है। उपरोक्त हैंडलर को ring/utilलाइब्रेरी का उपयोग करके अधिक संक्षिप्त रूप से परिभाषित किया जा सकता है ।

(use 'ring.util.response)

(defn handler [request]
  (response "Hello World"))

अब हम अनुरोध के आधार पर विभिन्न हैंडलर को कॉल करना चाहते हैं। हम कुछ स्थिर रूटिंग ऐसा कर सकते हैं:

(defn handler [request]
  (or
    (if (= (:uri request) "/a") (response "Alpha"))
    (if (= (:uri request) "/b") (response "Beta"))))

और इसे इस तरह से रिफलेक्टर करें:

(defn a-route [request]
  (if (= (:uri request) "/a") (response "Alpha")))

(defn b-route [request]
  (if (= (:uri request) "/b") (response "Beta"))))

(defn handler [request]
  (or (a-route request)
      (b-route request)))

दिलचस्प बात यह है कि तब जेम्स नोट करता है कि यह घोंसले के मार्गों की अनुमति देता है, क्योंकि "दो या अधिक मार्गों को एक साथ मिलाने का परिणाम स्वयं एक मार्ग है"।

(defn ab-routes [request]
  (or (a-route request)
      (b-route request)))

(defn cd-routes [request]
  (or (c-route request)
      (d-route request)))

(defn handler [request]
  (or (ab-routes request)
      (cd-routes request)))

अब तक, हम कुछ कोड को देखने लगे हैं जो ऐसा लगता है कि मैक्रो का उपयोग करके इसे फैक्टर किया जा सकता है। कंपोजर एक defroutesमैक्रो प्रदान करता है :

(defroutes ab-routes a-route b-route)

;; is identical to

(def ab-routes (routes a-route b-route))

कंपोजर मैक्रो की तरह अन्य मैक्रो प्रदान करता है GET:

(GET "/a" [] "Alpha")

;; will expand to

(fn [request#]
  (if (and (= (:request-method request#) ~http-method)
           (= (:uri request#) ~uri))
    (let [~bindings request#]
      ~@body)))

उत्पन्न अंतिम कार्य हमारे हैंडलर की तरह दिखता है!

कृपया जेम्स पोस्ट की जांच करना सुनिश्चित करें , क्योंकि यह अधिक विस्तृत स्पष्टीकरण में जाता है।


4

जो लोग अभी भी यह जानने के लिए संघर्ष कर रहे हैं कि मार्गों के साथ क्या हो रहा है, यह हो सकता है कि, मेरी तरह, आप विनाश के विचार को न समझें।

वास्तव में डॉक्स कोlet पढ़ने में मदद करने के लिए पूरे स्पष्ट "जादू के मूल्य कहां से आते हैं?" सवाल।

मैं नीचे संबंधित अनुभागों को चिपका रहा हूं:

क्लोजर अमूर्त संरचनात्मक बंधन का समर्थन करता है, जिसे अक्सर विनाशकारी कहा जाता है, चलो बाध्यकारी सूचियों, fn पैरामीटर सूचियों, और किसी भी मैक्रो जो एक या fn में विस्तार करता है। मूल विचार यह है कि एक बाइंडिंग-फॉर्म एक डेटा संरचना शाब्दिक हो सकता है जिसमें प्रतीक होते हैं जो कि init-expr के संबंधित भागों से बंधे होते हैं। बाइंडिंग अमूर्त है कि एक वेक्टर शाब्दिक कुछ भी है जो अनुक्रमिक है, के लिए बाध्य कर सकता है, जबकि एक नक्शा शाब्दिक कुछ भी है जो साहचर्य के लिए बाध्य कर सकता है।

वेक्टर बाइंडिंग-एक्सपर्स आपको नामों को अनुक्रमिक चीजों के हिस्सों (केवल वैक्टर नहीं) से बांधने की अनुमति देता है, जैसे कि वैक्टर, सूचियां, seq, स्ट्रिंग्स, सरणियां और कुछ भी जो nth का समर्थन करता है। मूल अनुक्रमिक रूप बाध्यकारी-रूपों का एक वेक्टर है, जो कि init-expr से क्रमिक तत्वों के लिए बाध्य होगा, nth के माध्यम से देखा गया। इसके अलावा, और वैकल्पिक रूप से, और उसके बाद एक बाध्यकारी-रूपों का कारण होगा कि बंधन-रूप अनुक्रम के शेष हिस्से से बंधे होने का मतलब है, अर्थात वह हिस्सा जो अभी तक बाध्य नहीं है, नेथनक्स के माध्यम से देखा। अंत में, वैकल्पिक भी: जैसा कि एक प्रतीक द्वारा पीछा किया जाएगा कि प्रतीक पूरे init-expr के लिए बाध्य हो जाएगा:

(let [[a b c & d :as e] [1 2 3 4 5 6 7]]
  [a b c d e])
->[1 2 3 (4 5 6 7) [1 2 3 4 5 6 7]]

वेक्टर बाइंडिंग-एक्सपर्स आपको नामों को अनुक्रमिक चीजों के हिस्सों (केवल वैक्टर नहीं) से बांधने की अनुमति देता है, जैसे कि वैक्टर, सूचियां, seq, स्ट्रिंग्स, सरणियां और कुछ भी जो nth का समर्थन करता है। मूल अनुक्रमिक रूप बाध्यकारी-रूपों का एक वेक्टर है, जो कि init-expr से क्रमिक तत्वों के लिए बाध्य होगा, nth के माध्यम से देखा गया। इसके अलावा, और वैकल्पिक रूप से, और उसके बाद एक बाध्यकारी-रूपों का कारण होगा कि बंधन-रूप अनुक्रम के शेष हिस्से से बंधे होने का मतलब है, अर्थात वह हिस्सा जो अभी तक बाध्य नहीं है, नेथनक्स के माध्यम से देखा। अंत में, वैकल्पिक भी: जैसा कि एक प्रतीक द्वारा पीछा किया जाएगा कि प्रतीक पूरे init-expr के लिए बाध्य हो जाएगा:

(let [[a b c & d :as e] [1 2 3 4 5 6 7]]
  [a b c d e])
->[1 2 3 (4 5 6 7) [1 2 3 4 5 6 7]]

3

मैंने अभी तक clojure वेब सामान पर शुरुआत नहीं की है, लेकिन, मैं यहाँ मेरे द्वारा बुकमार्क किए गए सामान को देखूंगा।


धन्यवाद, ये लिंक निश्चित रूप से सहायक हैं। मैं दिन के बेहतर हिस्से के लिए इस समस्या पर काम कर रहा हूं और इसके साथ एक बेहतर जगह पर हूं ... मैं किसी बिंदु पर अनुवर्ती पोस्ट करने की कोशिश करूंगा।
सीन वुड्स

1

विनाशकारी ({फॉर्म-परमेस: फॉर्म-परमेस}) के साथ क्या सौदा है? विनाश के समय मेरे लिए कौन से कीवर्ड उपलब्ध हैं?

उपलब्ध कुंजी वे हैं जो इनपुट मानचित्र में हैं। विनाशकारी लेट और डोज़क रूपों के अंदर, या मापदंडों के अंदर एफएन या डीएनएन के लिए उपलब्ध है

निम्नलिखित कोड उम्मीद है कि जानकारीपूर्ण होगा:

(let [{a :thing-a
       c :thing-c :as things} {:thing-a 0
                               :thing-b 1
                               :thing-c 2}]
  [a c (keys things)])

=> [0 2 (:thing-b :thing-a :thing-c)]

एक और अधिक उन्नत उदाहरण, नेस्टेड विनाशकारी दिखा रहा है:

user> (let [{thing-id :id
             {thing-color :color :as props} :properties} {:id 1
                                                          :properties {:shape
                                                                       "square"
                                                                       :color
                                                                       0xffffff}}]
            [thing-id thing-color (keys props)])
=> [1 16777215 (:color :shape)]

जब बुद्धिमानी से उपयोग किया जाता है, तो बायलरप्लेट डेटा एक्सेस से बचकर आपके कोड को नष्ट कर देता है। का उपयोग करके: परिणाम को प्रिंट करने और (या परिणाम की कुंजी) आप एक बेहतर विचार प्राप्त कर सकते हैं कि आप किस अन्य डेटा तक पहुंच सकते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.