Antworten:
Eine Funktion kann mehrere Signaturen haben, wenn sich die Signaturen in ihrer Arität unterscheiden. Damit können Sie Standardwerte angeben.
(defn string->integer
([s] (string->integer s 10))
([s base] (Integer/parseInt s base)))
Beachten Sie, dass unter der Annahme , falseund nilbeide nicht-Werte betrachtet, (if (nil? base) 10 base)könnte verkürzt werden (if base base 10), oder weiter zu (or base 10).
recurnur mit derselben Arität gearbeitet. Wenn Sie oben versucht haben, zum Beispiel:java.lang.IllegalArgumentException: Mismatched argument count to recur, expected: 1 args, got: 2, compiling:
(string->integer s 10))?
Sie können restArgumente seit Clojure 1.2 [ ref ] auch als Map zerstören . Auf diese Weise können Sie Funktionsargumente benennen und Standardeinstellungen angeben:
(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)
Diese Lösung ist dem Geist der ursprünglichen Lösung näher , aber geringfügig sauberer
(defn string->integer [str & [base]]
(Integer/parseInt str (or base 10)))
Ein ähnliches Muster, das nützlich sein kann, orkombiniert mitlet
(defn string->integer [str & [base]]
(let [base (or base 10)]
(Integer/parseInt str base)))
In diesem Fall ist dies zwar ausführlicher, es kann jedoch hilfreich sein, wenn die Standardeinstellungen von anderen Eingabewerten abhängen sollen . 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 auch mit benannten Argumenten zu arbeiten (wie in der Lösung von M. Gilliar):
(defn exemplar [a & {:keys [b c]}]
(let [b (or b 5)
c (or c (* 7 b))]
(println a b c)))
Oder noch mehr Fusion:
(defn exemplar [a & {:keys [b c] :or {b 5}}]
(let [c (or c (* 7 b))]
(println a b c)))
or
orist anders als :orda orkennt den Unterschied von nilund nicht false.
Es gibt noch einen anderen Ansatz, den Sie in Betracht ziehen sollten: Teilfunktionen . Dies ist wohl eine "funktionalere" und flexiblere Möglichkeit, Standardwerte für Funktionen anzugeben.
Erstellen Sie zunächst (falls erforderlich) eine Funktion mit den Parametern, die Sie als Standardparameter als Hauptparameter bereitstellen möchten:
(defn string->integer [base str]
(Integer/parseInt str base))
Dies geschieht, weil Sie mit Clojures Version von partialdie "Standard" -Werte nur in der Reihenfolge angeben können, in der sie in der Funktionsdefinition angezeigt werden. Nachdem die Parameter wie gewünscht bestellt wurden, können Sie mit der folgenden partialFunktion eine "Standard" -Version der Funktion erstellen :
(partial string->integer 10)
Um diese Funktion mehrmals aufrufbar zu machen, können Sie sie in eine Variable einfügen, indem Sie Folgendes verwenden def:
(def decimal (partial string->integer 10))
(decimal "10")
;10
Sie können auch einen "lokalen Standard" erstellen, indem Sie let:
(let [hex (partial string->integer 16)]
(* (hex "FF") (hex "AA")))
;43350
Der Teilfunktionsansatz hat einen entscheidenden Vorteil gegenüber den anderen: Der Benutzer der Funktion kann weiterhin entscheiden, wie hoch der Standardwert sein soll, und nicht der Hersteller der Funktion, ohne die Funktionsdefinition ändern zu müssen . Dies wird in dem Beispiel veranschaulicht, in dem hexich entschieden habe, dass die Standardfunktion decimalnicht 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 möglicherweise aussagekräftiger ist und / oder einen anderen Bereich (var, local). Falls gewünscht, kann die Teilfunktion auch mit einigen der oben genannten 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 geringfügig von Brians Antwort abweicht, da die Reihenfolge der Parameter aus den oben in dieser Antwort angegebenen Gründen umgekehrt wurde.)
Sie können sich auch https://clojuredocs.org/clojure.core/fnil ansehen(fnil)
(recur s 10),recuranstatt den Funktionsnamen zu wiederholenstring->integer. Das würde es in Zukunft einfacher machen, die Funktion umzubenennen. Kennt jemand einen Grund,recurin diesen Situationen nicht zu verwenden ?