wake-up-neo.com

So erstellen Sie einen Standardwert für das Funktionsargument in Clojure

Ich komme mit diesem:

 (defn string-> integer [str & [base]] 
 (Integer/parseInt str (falls (null? base) 10 base))) 
 
 (string-> integer "10") 
 (string-> integer "FF" 16) 

Aber es muss ein besserer Weg sein, dies zu tun.

119
jcubic

Eine Funktion kann mehrere Signaturen haben, wenn sich die Signaturen in ihrer Arität unterscheiden. Sie können dies verwenden, um Standardwerte anzugeben.

(defn string->integer 
  ([s] (string->integer s 10))
  ([s base] (Integer/parseInt s base)))

Beachten Sie, dass unter der Annahme, dass false und nil beide als Nichtwerte betrachtet werden, (if (nil? base) 10 base) Auf (if base base 10) Oder weiter auf (or base 10) Abgekürzt werden könnte.

157
Brian Carper

Seit Clojure 1.2 können Sie auch rest Argumente als Map destrukturieren [ ref ]. Auf diese Weise können Sie Funktionsargumente benennen und die Standardeinstellungen festlegen:

(defn string->integer [s & {:keys [base] :or {base 10}}]
    (Integer/parseInt s base))

Jetzt können Sie anrufen

(string->integer "11")
=> 11

oder

(string->integer "11" :base 8)
=> 9

Sie können dies hier in Aktion sehen: https://github.com/Raynes/clavatar/blob/master/src/clavatar/core.clj (zum Beispiel)

148

Diese Lösung entspricht eher dem Geist der ursprünglichen Lösung , ist jedoch geringfügig sauberer

(defn string->integer [str & [base]]
  (Integer/parseInt str (or base 10)))

Ein ähnliches Muster , das nützlich sein kann, verwendet or kombiniert mit let

(defn string->integer [str & [base]]
  (let [base (or base 10)]
    (Integer/parseInt str base)))

In diesem Fall ist es zwar ausführlicher, aber hilfreich, wenn Sie möchten, dass die Standardeinstellungen von anderen Eingabewerten abhängen . Betrachten Sie beispielsweise die folgende Funktion:

(defn exemplar [a & [b c]]
  (let [b (or b 5)
        c (or c (* 7 b))]
    ;; or whatever yer actual code might be...
    (println a b c)))

(exemplar 3) => 3 5 35

Dieser Ansatz kann leicht erweitert werden, um mit benannten Argumenten (wie in der Lösung von M. Gilliar) zu arbeiten:

(defn exemplar [a & {:keys [b c]}]
  (let [b (or b 5)
        c (or c (* 7 b))]
    (println a b c)))

Oder mit noch mehr einer Fusion:

(defn exemplar [a & {:keys [b c] :or {b 5}}]
  (let [c (or c (* 7 b))]
    (println a b c)))
33
metasoarous

Es gibt einen anderen Ansatz, den Sie in Betracht ziehen sollten: partielle Funktionen. Dies ist wahrscheinlich eine "funktionalere" und flexiblere Möglichkeit, Standardwerte für Funktionen anzugeben.

Beginnen Sie, indem Sie (falls erforderlich) eine Funktion erstellen, die die Parameter enthält, die Sie als Standardparameter als führende Parameter bereitstellen möchten:

(defn string->integer [base str]
  (Integer/parseInt str base))

Dies geschieht, weil Sie in Clojures Version von partial die "Standard" -Werte nur in der Reihenfolge angeben können, in der sie in der Funktionsdefinition erscheinen. Nachdem die Parameter wie gewünscht bestellt wurden, können Sie mit der Funktion partial eine "Standard" -Version der Funktion erstellen:

(partial string->integer 10)

Um diese Funktion mehrfach aufrufbar zu machen, können Sie sie mit def in eine Variable einfügen:

(def decimal (partial string->integer 10))
(decimal "10")
;10

Sie können auch einen "lokalen Standard" mit let erstellen:

(let [hex (partial string->integer 16)]
  (* (hex "FF") (hex "AA")))
;43350

Der Teilfunktionsansatz hat einen entscheidenden Vorteil gegenüber den anderen: Der Verbraucher der Funktion kann immer noch entscheiden, welcher Standardwert verwendet wird, und nicht der Erzeuger des Funktion , ohne dass die Funktionsdefinition geändert werden muss . Dies wird in dem Beispiel mit hex veranschaulicht, in dem ich entschieden habe, dass die Standardfunktion decimal nicht das ist, was ich will.

Ein weiterer Vorteil dieses Ansatzes besteht darin, dass Sie der Standardfunktion einen anderen Namen (dezimal, hexadezimal usw.) zuweisen können, der aussagekräftiger und/oder in einem anderen Bereich (var, local) sein kann. Falls gewünscht, kann die Teilfunktion auch mit einigen der obigen Ansätze gemischt werden:

(defn string->integer 
  ([s] (string->integer s 10))
  ([base s] (Integer/parseInt s base)))

(def hex (partial string->integer 16))

(Beachten Sie, dass dies etwas anders ist als die Antwort von Brian, da die Reihenfolge der Parameter aus den oben in dieser Antwort angegebenen Gründen umgekehrt wurde.)

8
optevo

Du könntest auch nachsehen in (fnil)https://clojuredocs.org/clojure.core/fnil

5
celwell