Відповіді:
Функція може мати декілька підписів, якщо підписи відрізняються за сутністю. Ви можете використовувати це для введення значень за замовчуванням.
(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
працює лише на одній аристократиці. якщо ви спробували повторити вище, наприклад:java.lang.IllegalArgumentException: Mismatched argument count to recur, expected: 1 args, got: 2, compiling:
(string->integer s 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)))
Аналогічна картина , яка може бути зручно використання в 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
or
відрізняється від :or
того, or
що не знає різниці nil
і false
.
Ви можете скористатися ще одним підходом: часткові функції. Це, мабуть, більш "функціональний" і гнучкіший спосіб визначення значень за замовчуванням для функцій.
Почніть зі створення (за необхідності) функції, яка має параметри (параметри), які ви хочете надати за замовчуванням, як провідні параметри:
(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
(recur s 10)
, використовуючиrecur
замість повторення назви функціїstring->integer
. Це полегшить перейменування функції в майбутньому. Хтось знає якусь причину не використовуватиrecur
в цих ситуаціях?