Jawaban:
Suatu fungsi dapat memiliki beberapa tanda tangan jika tanda tangan berbeda dalam arity. Anda dapat menggunakannya untuk memberikan nilai default.
(defn string->integer
([s] (string->integer s 10))
([s base] (Integer/parseInt s base)))
Perhatikan bahwa asumsi false
dan nil
keduanya dianggap tidak bernilai, (if (nil? base) 10 base)
dapat disingkat menjadi (if base base 10)
, atau lebih jauh (or base 10)
.
recur
hanya bekerja pada arity yang sama. jika Anda mencoba berulang di atas, misalnya:java.lang.IllegalArgumentException: Mismatched argument count to recur, expected: 1 args, got: 2, compiling:
(string->integer s 10)
)?
Anda juga dapat merusak rest
argumen sebagai peta sejak Clojure 1.2 [ ref ]. Ini memungkinkan Anda memberi nama dan memberikan default untuk argumen fungsi:
(defn string->integer [s & {:keys [base] :or {base 10}}]
(Integer/parseInt s base))
Sekarang kamu bisa menelepon
(string->integer "11")
=> 11
atau
(string->integer "11" :base 8)
=> 9
Anda dapat melihat ini dalam aksi di sini: https://github.com/Raynes/cl[/blob/master/src/cl[/core.clj (misalnya)
Solusi ini lebih dekat dengan semangat solusi asli , tetapi sedikit lebih bersih
(defn string->integer [str & [base]]
(Integer/parseInt str (or base 10)))
Sebuah pola yang sama yang dapat menggunakan berguna or
dikombinasikan denganlet
(defn string->integer [str & [base]]
(let [base (or base 10)]
(Integer/parseInt str base)))
Meskipun dalam hal ini lebih banyak bertele-tele, ini dapat bermanfaat jika Anda ingin memiliki standar bergantung pada nilai input lainnya . Misalnya, pertimbangkan fungsi berikut:
(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
Pendekatan ini dapat dengan mudah diperluas untuk bekerja dengan argumen bernama (seperti dalam solusi M. Gilliar) juga:
(defn exemplar [a & {:keys [b c]}]
(let [b (or b 5)
c (or c (* 7 b))]
(println a b c)))
Atau menggunakan lebih banyak perpaduan:
(defn exemplar [a & {:keys [b c] :or {b 5}}]
(let [c (or c (* 7 b))]
(println a b c)))
or
or
berbeda dari :or
karena or
tidak tahu perbedaan nil
dan false
.
Ada pendekatan lain yang mungkin ingin Anda pertimbangkan: fungsi parsial . Ini bisa dibilang cara yang lebih "fungsional" dan lebih fleksibel untuk menentukan nilai default untuk fungsi.
Mulailah dengan membuat (jika perlu) fungsi yang memiliki parameter yang ingin Anda berikan sebagai default sebagai parameter utama:
(defn string->integer [base str]
(Integer/parseInt str base))
Ini dilakukan karena versi Clojure partial
memungkinkan Anda memberikan nilai "default" hanya dalam urutan yang muncul dalam definisi fungsi. Setelah parameter telah dipesan sesuai keinginan, Anda kemudian dapat membuat versi "default" dari fungsi menggunakan partial
fungsi:
(partial string->integer 10)
Untuk membuat fungsi ini bisa dipanggil beberapa kali, Anda bisa meletakkannya di var menggunakan def
:
(def decimal (partial string->integer 10))
(decimal "10")
;10
Anda juga dapat membuat "default lokal" menggunakan let
:
(let [hex (partial string->integer 16)]
(* (hex "FF") (hex "AA")))
;43350
Pendekatan fungsi parsial memiliki satu keunggulan utama dibandingkan yang lain: konsumen fungsi masih dapat memutuskan apa nilai default akan menjadi daripada produsen fungsi tanpa perlu memodifikasi definisi fungsi . Ini diilustrasikan dalam contoh di hex
mana saya telah memutuskan bahwa fungsi default decimal
bukan yang saya inginkan.
Keuntungan lain dari pendekatan ini adalah Anda dapat menetapkan fungsi default nama yang berbeda (desimal, hex, dll) yang mungkin lebih deskriptif dan / atau cakupan yang berbeda (var, lokal). Fungsi parsial juga dapat dicampur dengan beberapa pendekatan di atas jika diinginkan:
(defn string->integer
([s] (string->integer s 10))
([base s] (Integer/parseInt s base)))
(def hex (partial string->integer 16))
(Perhatikan ini sedikit berbeda dari jawaban Brian karena urutan parameter telah dibalik karena alasan yang diberikan di bagian atas respons ini)
Anda mungkin juga melihat ke (fnil)
https://clojuredocs.org/clojure.core/fnil
(recur s 10)
, menggunakanrecur
alih-alih mengulangi nama fungsistring->integer
. Itu akan membuatnya lebih mudah untuk mengubah nama fungsi di masa depan. Adakah yang tahu alasan untuk tidak menggunakanrecur
dalam situasi ini?