![](/img/trans.png)
[英]How to create an std::function as method argument with std::stoi as default value?
[英]How to create default value for function argument in Clojure
我带着这个:
(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)
。
自 Clojure 1.2 [ ref ] 起,您还可以将rest
参数解构为映射。 这使您可以为函数参数命名并提供默认值:
(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)))
您可能需要考虑另一种方法:偏函数。 这些可以说是为函数指定默认值的更“功能性”和更灵活的方式。
首先创建(如有必要)一个函数,该函数具有您希望作为默认值提供的参数作为前导参数:
(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
与 Matthew 的建议非常相似的方法是不执行&
rest args,而是要求调用者提供灵活(和可选)键的单个额外 map 参数。
(defn string->integer [s {:keys [base] :or {base 10}}]
(Integer/parseInt s base))
(string->integer "11" {:base 8})
=> 9
(string->integer "11" {})
=> 11
这样做的好处是选项是单个参数映射,调用者不必非常小心传递偶数个额外参数。 另外,linters 可以用这种风格做得更好。 与每行成对的 args 相比,编辑器还应该在地图键值表格对齐方面做得更好(如果您愿意的话)。
稍有不利的一面是,在没有选项的情况下调用时,仍必须提供空映射。
这在这个位置参数部分(代码气味文章)中有所涉及。
更新:现在 Clojure 1.11 支持传递可选参数的映射(使用&
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.