![](/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.