Answers:
如果签名的性质不同,一个函数可以具有多个签名。您可以使用它来提供默认值。
(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
也可以轻松地将此方法扩展为使用命名参数(如M. Gilliar的解决方案):
(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)
为了使该函数可多次调用,可以使用def
以下命令将其放在var中:
(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))
(请注意,这与Brian的回答略有不同,因为出于此响应顶部给出的原因,参数的顺序已颠倒)
您可能还会查看(fnil)
https://clojuredocs.org/clojure.core/fnil
(recur s 10)
,使用recur
代替重复的功能名称string->integer
。这将使将来更容易重命名该功能。有谁知道recur
在这些情况下不使用的任何理由?