Как создать значение по умолчанию для аргумента функции в Clojure
Я пришел с этой:
(defn string->integer [str & [base]] (Integer/parseInt str (if (nil? base) 10 base))) (string->integer "10") (string->integer "FF" 16)
но это должен быть лучший способ, чтобы сделать это.
5 ответов:
функция может иметь несколько подписей, если подписи отличаются по арности. Вы можете использовать значения по умолчанию.
(defn string->integer ([s] (string->integer s 10)) ([s base] (Integer/parseInt s base)))
обратите внимание, что при условии
false
иnil
оба считаются не значениями,(if (nil? base) 10 base)
можно сократить до(if base base 10)
, и далее(or base 10)
.
вы также можете уничтожить
rest
аргументы как карта с Clojure 1.2 [ ref]. Это позволяет задать имя и значения по умолчанию для аргументов функции:(defn string->integer [s & {:keys [base] :or {base 10}}] (Integer/parseInt s base))
теперь вы можете звонить
(string->integer "11") => 11
или
(string->integer "11" :base 8) => 9
вы можете увидеть это в действии здесь:https://github.com/Raynes/clavatar/blob/master/src/clavatar/core.clj (например)
это решение ближе к дух оригинального решения, но незначительно чище
(defn string->integer [str & [base]] (Integer/parseInt str (or base 10)))
A аналогичная картина что может быть удобно использовать
or
в сочетании сlet
(defn string->integer [str & [base]] (let [base (or base 10)] (Integer/parseInt str base)))
хотя в этом случае более подробно, это может быть полезно, если вы хотите иметь значения по умолчанию зависят от других входных значений. Например, рассмотрим следующую функцию:
(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
этот подход может быть легко расширен для работы с именованные аргументы (как и в решении М. Гиллиара), а также:
(defn exemplar [a & {:keys [b c]}] (let [b (or b 5) c (or c (* 7 b))] (println a b c)))
или, используя еще больше фьюжн:
(defn exemplar [a & {:keys [b c] :or {b 5}}] (let [c (or c (* 7 b))] (println a b c)))
есть еще один подход, который вы можете рассмотреть:частичная функции. Это, возможно, более "функциональный" и более гибкий способ указать значения по умолчанию для функций.
начните с создания(при необходимости) функции, которая имеет параметр(Ы), который вы хотите предоставить по умолчанию в качестве ведущего параметра(ов):
(defn string->integer [base str] (Integer/parseInt str base))
это делается потому, что версия Clojure
partial
позволяет указать значения "по умолчанию" только в порядке они появляются в определении функции. После того, как параметры были упорядочены по желанию, вы можете создать версию функции "по умолчанию" с помощьюpartial
функция:(partial string->integer 10)
чтобы сделать эту функцию вызываемой несколько раз, вы можете поместить ее в var с помощью
def
:(def decimal (partial string->integer 10)) (decimal "10") ;10
вы также можете создать "локальное значение по умолчанию" с помощью
let
:(let [hex (partial string->integer 16)] (* (hex "FF") (hex "AA"))) ;43350
подход с частичной функцией имеет одно ключевое преимущество перед другими: потребитель функции все еще могут решать, что значение по умолчанию будет, а не производитель функции без необходимости изменять определение функции. Это проиллюстрировано в Примере с
hex
где я решил, что функция по умолчаниюdecimal
это не то, что я хочу.еще одно преимущество этого подхода заключается в том, что вы можете назначить функции по умолчанию другое имя (десятичное, шестнадцатеричное и т. д.), которое может быть больше описательная и / или другая область (var, local). Частичная функция также может быть смешана с некоторыми из подходов выше, если это необходимо:
(defn string->integer ([s] (string->integer s 10)) ([base s] (Integer/parseInt s base))) (def hex (partial string->integer 16))
(обратите внимание, что это немного отличается от ответа Брайана, поскольку порядок параметров был изменен по причинам, указанным в верхней части этого ответа)
вы также можете посмотреть на
(fnil)
https://clojuredocs.org/clojure.core/fnil