Clojure - benannte Argumente


78

Hat Clojure Argumente benannt? Wenn ja, können Sie bitte ein kleines Beispiel dafür geben?

Antworten:


118

In Clojure 1.2 können Sie das restArgument genauso zerstören, wie Sie eine Karte zerstören würden. Dies bedeutet, dass Sie benannte nicht positionelle Schlüsselwortargumente ausführen können. Hier ist ein Beispiel:

user> (defn blah [& {:keys [key1 key2 key3]}] (str key1 key2 key3))
#'user/blah
user> (blah :key1 "Hai" :key2 " there" :key3 10)
"Hai there10"
user> (blah :key1 "Hai" :key2 " there")
"Hai there"
user> (defn blah [& {:keys [key1 key2 key3] :as everything}] everything)
#'user/blah
user> (blah :key1 "Hai" :key2 " there")
{:key2 " there", :key1 "Hai"}

Alles , was Sie tun können, während Sie eine Clojure-Map zerstören, können Sie wie oben gezeigt in der Argumentliste einer Funktion ausführen. Einschließlich der Verwendung von: oder zum Definieren von Standardeinstellungen für die folgenden Argumente:

user> (defn blah [& {:keys [key1 key2 key3] :or {key3 10}}] (str key1 key2 key3))
#'user/blah
user> (blah :key1 "Hai" :key2 " there")
"Hai there10"

Dies ist jedoch in Clojure 1.2. Alternativ können Sie in älteren Versionen Folgendes tun, um dasselbe zu simulieren:

user> (defn blah [& rest] (let [{:keys [key1 key2 key3] :or {key3 10}} (apply hash-map rest)] (str key1 key2 key3)))
#'user/blah
user> (blah :key1 "Hai" :key2 " there")
"Hai there10"

und das funktioniert im Allgemeinen genauso.

Sie können auch Positionsargumente vor den Schlüsselwortargumenten haben:

user> (defn blah [x y & {:keys [key1 key2 key3] :or {key3 10}}] (str x y key1 key2 key3))
#'user/blah
user> (blah "x" "Y" :key1 "Hai" :key2 " there")
"xYHai there10"

Diese sind nicht optional und müssen bereitgestellt werden.

Sie können das restArgument tatsächlich wie jede Clojure-Sammlung zerstören .

user> (defn blah [& [one two & more]] (str one two "and the rest: " more))
#'user/blah
user> (blah 1 2 "ressssssst")
"12and the rest: (\"ressssssst\")"

Sie können so etwas sogar in Clojure 1.1 tun. Die Destrukturierung im Map-Stil für Keyword-Argumente erfolgte jedoch erst in Version 1.2.


34

Zusätzlich zu Raynes 'hervorragender Antwort gibt es in Clojure-Contrib ein Makro , das das Leben leichter macht:

user => (benutze '[clojure.contrib.def: only [defnk]])
Null
user => (defnk foo [ab: c 8: d 9] 
         [A B C D])
# 'user / foo
Benutzer => (foo 1 2)
[1 2 8 9]
Benutzer => (foo 1 2 3)
java.lang.IllegalArgumentException: Für Schlüssel: 3 wird kein Wert angegeben (NO_SOURCE_FILE: 0)
Benutzer => (foo 1 2: c 3)
[1 2 3 9]

6
Das habe ich vergessen zu erwähnen! Ich war alle damit beschäftigt, die zehntausend Möglichkeiten aufzuzeigen, wie Clojure Dinge zerstören kann. : p
Rayne

1
Clojure-Contrib ist veraltet und ich konnte keine aktuelle Alternative finden. Irgendwelche Ideen?
Lstor

2
@Lstor: überprüfen Sie defnk in prismatic / Sanitär
Ian

3

Ab Clojure Version 1.8 scheint die Keyword-Unterstützung noch ein bisschen meh zu sein .

Sie können Schlüsselwortargumente wie folgt angeben:

(defn myfn1
  "Specifying keyword arguments without default values"
  [& {:keys [arg1 arg2]}]
  (list arg1 arg2))

Beispiele für die Bezeichnung:

(myfn1 :arg1 23 :arg2 45)  --> evaluates to (23 45)
(myfn1 :arg1 22)           --> evaluates to (22 nil)

Wenn Sie Standardwerte für diese Schlüsselwortargumente angeben möchten:

(defn myfn2
  "Another version, this time with default values specified"
  [& {:keys [arg1 arg2] :or {arg1 45 arg2 55}}]
  (list arg1 arg2))

Dies macht das erwartete im zweiten Fall:

(myfn2 :arg1 22)           --> evaluates to (22 55)

Jeder Teil jeder Sprache hat Vor- und Nachteile, aber nur zum Vergleich: So würden Sie in Common Lisp dasselbe tun:

(defun myfn3
    (&key arg1 arg2)
    "Look Ma, keyword args!"
    (list arg1 arg2))

(defun myfn4
    (&key (arg1 45) (arg2 55))
    "Once again, with default values"
    (list arg1 arg2))

0

Meinen Sie vielleicht benannte Parameter ? Diese sind nicht direkt verfügbar, aber Sie können diesen Vektoransatz verwenden, wenn Sie möchten, wodurch Sie möglicherweise das bekommen, was Sie wollen.

Bei RosettaCode gibt es eine ausführlichere Erklärung, wie dies mithilfe von Destrukturierung geschehen kann .


3
@Abel Können Sie die Beispiele teilen, auf die Sie verlinken? (Sie haben eine Möglichkeit, sich zu ändern oder veraltet zu sein).
David J.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.