我带着这个来:
(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)
。rest
参数解构为一个映射,这样可以为函数参数命名并提供默认值。[参考链接]。(defn string->integer [s & {:keys [base] :or {base 10}}]
(Integer/parseInt s base))
(string->integer "11")
=> 11
或者
(string->integer "11" :base 8)
=> 9
这个解决方案更接近于原始解决方案的精神,但稍微更清晰一些。
(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
更加简洁。 - johnbakersor
与:or
不同,因为or
无法区分nil
和false
的差异。 - Xiangru Lian还有一种方法您可能想考虑:使用partial函数。这些函数可以被认为是指定函数默认值更加“函数式”和灵活的方式。
首先,创建(如果需要)一个具有所需提供默认值的参数作为前导参数的函数:
(defn string->integer [base str]
(Integer/parseInt str base))
这是因为Clojure版本的partial
只能让你按照函数定义中的顺序提供“默认”值。一旦参数按照所需顺序排列,你就可以使用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
替换为另一个函数。
这种方法的另一个优势是可以给默认函数赋予不同的名称(如 decimal、hex 等),这样可能更加描述性或适用于不同的作用域(var、local)。如果需要,也可以将部分函数与上述某些方法混合使用。
(defn string->integer
([s] (string->integer s 10))
([base s] (Integer/parseInt s base)))
(def hex (partial string->integer 16))
(请注意,这与布赖恩的答案略有不同,因为参数的顺序已经改变,原因在本回复顶部给出)
&
rest参数,而是要求调用者提供灵活(可选)的键的单个额外映射参数。(defn string->integer [s {:keys [base] :or {base 10}}]
(Integer/parseInt s base))
(string->integer "11" {:base 8})
=> 9
(string->integer "11" {})
=> 11
&
传递可选参数的参数映射(链接)。&
,但您已经说过这是区别所在。 - jcubic
(recur s 10)
,使用recur
代替重复函数名string->integer
。这样可以更轻松地在将来更改函数名称。有人知道在这些情况下不使用recur
的原因吗? - Rory O'Kanerecur
只能在相同的 arity 上工作。例如,如果您尝试在上面使用 recur,会出现以下错误:java.lang.IllegalArgumentException: Mismatched argument count to recur, expected: 1 args, got: 2, compiling:
- djhaskin987(string->integer s 10)
)? - Kurt Mueller