Я пришел с этим:
(defn string->integer [str & [base]] (Integer/parseInt str (if (nil? base) 10 base))) (string->integer "10") (string->integer "FF" 16)
Но это должен быть лучший способ сделать это.
Я пришел с этим:
(defn string->integer [str & [base]] (Integer/parseInt str (if (nil? base) 10 base))) (string->integer "10") (string->integer "FF" 16)
Но это должен быть лучший способ сделать это.
Функция может иметь несколько подписей, если подписи различаются по арности. Вы можете использовать это для предоставления значений по умолчанию.
(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)
.
(recur s 10)
, используя recur
< / a> вместо повторения имени функции string->integer
. Это упростило бы переименование функции в будущем. Кто-нибудь знает причину не использовать recur
в таких ситуациях?
- person Rory O'Kane; 10.08.2014
recur
работает только с той же арностью. если вы пробовали повторить выше, например: java.lang.IllegalArgumentException: Mismatched argument count to recur, expected: 1 args, got: 2, compiling:
- person djhaskin987; 20.08.2014
(string->integer s 10)
)?
- person Kurt Mueller; 26.11.2015
Вы также можете деструктурировать rest
аргументы как карту, начиная с Clojure 1.2 [ref]. Это позволяет вам назвать и указать значения по умолчанию для аргументов функции:
(defn string->integer [s & {:keys [base] :or {base 10}}]
(Integer/parseInt s base))
Теперь ты можешь позвонить
(string->integer "11")
=> 11
or
(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)))
В похожем шаблоне, который может оказаться полезным, используется 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)))
or
- person johnbakers; 03.01.2014
or
отличается от :or
, поскольку or
не знает разницы между nil
и false
.
- person Xiangru Lian; 28.07.2015
Вы можете рассмотреть еще один подход: частичные функции. Возможно, это более «функциональный» и более гибкий способ указания значений по умолчанию для функций.
Начните с создания (при необходимости) функции, которая имеет параметр (ы), который вы хотите предоставить по умолчанию в качестве ведущего параметра (ов):
(defn string->integer [base str]
(Integer/parseInt str base))
Это сделано потому, что версия partial
в Clojure позволяет вам предоставлять значения «по умолчанию» только в том порядке, в котором они появляются в определении функции. После того, как параметры будут упорядочены по желанию, вы можете создать "стандартную" версию функции, используя функцию partial
:
(partial string->integer 10)
Чтобы сделать эту функцию вызываемой несколько раз, вы можете поместить ее в переменную, используя 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
Подход, очень похожий на предложение Мэтью, заключается в том, чтобы не использовать &
rest args, а потребовать, чтобы вызывающие стороны предоставили единственный дополнительный аргумент карты гибких (и необязательных) ключей.
(defn string->integer [s {:keys [base] :or {base 10}}]
(Integer/parseInt s base))
(string->integer "11" {:base 8})
=> 9
(string->integer "11" {})
=> 11
Преимущество этого состоит в том, что параметры представляют собой карту с одним аргументом, и вызывающей стороне не нужно быть настолько осторожным с передачей четного числа дополнительных аргументов. Кроме того, линтеры лучше подходят для этого стиля. Редакторы также должны лучше справляться с табличным выравниванием карты по ключу и значением (если вам это нравится), чем с парами аргументов на строку.
Небольшой недостаток заключается в том, что при вызове без параметров все равно должна быть предоставлена пустая карта.
Это затрагивается в этом разделе позиционных аргументов (статья о запахах кода).
ОБНОВЛЕНИЕ: в Clojure 1.11 теперь есть поддержка передача карты для дополнительных аргументов (с использованием &
).
&
, но вы сказали, что в этом разница.
- person jcubic; 31.12.2020