Yanıtlar:
İmzalar birbirlerinden farklıysa, bir işlevin birden çok imzası olabilir. Varsayılan değerleri sağlamak için bunu kullanabilirsiniz.
(defn string->integer
([s] (string->integer s 10))
([s base] (Integer/parseInt s base)))
Varsayımın false
ve nil
her ikisinin de değer dışı olarak kabul (if (nil? base) 10 base)
edildiğini (if base base 10)
, kısaltılabileceğini veya daha ileriye götürülebileceğini unutmayın (or base 10)
.
recur
sadece aynı arity üzerinde çalışıyor. yukarıda java.lang.IllegalArgumentException: Mismatched argument count to recur, expected: 1 args, got: 2, compiling:
(string->integer s 10)
mu (yani )?
rest
Clojure 1.2 [ ref ] sürümünden bu yana argümanları harita olarak da yok edebilirsiniz . Bu, işlev bağımsız değişkenleri için varsayılanları adlandırmanıza ve sağlamanıza olanak tanır:
(defn string->integer [s & {:keys [base] :or {base 10}}]
(Integer/parseInt s base))
Şimdi arayabilirsin
(string->integer "11")
=> 11
veya
(string->integer "11" :base 8)
=> 9
Bunu burada eylem halinde görebilirsiniz: https://github.com/Raynes/clavatar/blob/master/src/clavatar/core.clj (örneğin)
Bu çözüm, orijinal çözümün ruhuna daha yakın , ancak marjinal olarak daha temiz
(defn string->integer [str & [base]]
(Integer/parseInt str (or base 10)))
Bir Benzer bir model kullanışlı kullanımları olabilir or
kombinelet
(defn string->integer [str & [base]]
(let [base (or base 10)]
(Integer/parseInt str base)))
Bu durumda daha ayrıntılı olsa da, varsayılanların diğer girdi değerlerine bağlı olmasını istiyorsanız yararlı olabilir . Örneğin, aşağıdaki işlevi düşünün:
(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
Bu yaklaşım, adlandırılmış argümanlarla (M. Gilliar'ın çözümünde olduğu gibi) çalışacak şekilde kolayca genişletilebilir :
(defn exemplar [a & {:keys [b c]}]
(let [b (or b 5)
c (or c (* 7 b))]
(println a b c)))
Veya daha fazla füzyon kullanarak:
(defn exemplar [a & {:keys [b c] :or {b 5}}]
(let [c (or c (* 7 b))]
(println a b c)))
or
or
farklıdır :or
çünkü or
farkını bilmiyor nil
ve false
.
Göz önünde bulundurmak isteyebileceğiniz başka bir yaklaşım daha var: kısmi işlevler. Bunlar, muhtemelen işlevler için varsayılan değerleri belirlemenin daha "işlevsel" ve daha esnek bir yoludur.
Baştaki parametre (ler) olarak varsayılan olarak sağlamak istediğiniz parametre (ler) i içeren bir işlev oluşturarak başlayın (gerekirse):
(defn string->integer [base str]
(Integer/parseInt str base))
Bu, Clojure'un sürümü partial
"varsayılan" değerleri yalnızca işlev tanımında göründükleri sırada sağlamanıza izin verdiği için yapılır . Parametreler istendiği gibi sıralandıktan sonra, işlevi kullanarak işlevin "varsayılan" bir sürümünü oluşturabilirsiniz partial
:
(partial string->integer 10)
Bu işlevi birden çok kez çağrılabilir hale getirmek için, şunu kullanarak bir var'a koyabilirsiniz def
:
(def decimal (partial string->integer 10))
(decimal "10")
;10
Şunları kullanarak da bir "yerel varsayılan" oluşturabilirsiniz let
:
(let [hex (partial string->integer 16)]
(* (hex "FF") (hex "AA")))
;43350
Kısmi fonksiyon yaklaşımının diğerlerine göre bir önemli avantajı vardır: fonksiyonun tüketicisi , fonksiyon tanımını değiştirmeye gerek kalmadan fonksiyonun üreticisi yerine varsayılan değerin ne olacağına hala karar verebilir . Bu, varsayılan işlevin istediğim şey olmadığına karar verdiğim örnekte gösterilmiştir .hex
decimal
Bu yaklaşımın bir başka avantajı, varsayılan işleve daha açıklayıcı ve / veya farklı bir kapsam (var, yerel) olabilecek farklı bir ad (ondalık, onaltılık vb.) Atayabilmenizdir. Kısmi işlev, istenirse yukarıdaki bazı yaklaşımlarla da karıştırılabilir:
(defn string->integer
([s] (string->integer s 10))
([base s] (Integer/parseInt s base)))
(def hex (partial string->integer 16))
(Bu yanıtın üst kısmında verilen nedenlerle parametrelerin sırası tersine çevrildiğinden, bunun Brian'ın yanıtından biraz farklı olduğunu unutmayın)
Ayrıca https://clojuredocs.org/clojure.core/fnil adresine de bakabilirsiniz.(fnil)
(recur s 10)
kullanmak daha iyi olur . Bu, gelecekte işlevi yeniden adlandırmayı kolaylaştırır. Bu durumlarda kullanmamak için herhangi bir sebep bilen var mı ?recur
string->integer
recur