推敲你的函數參數表

「推敲」這個詞來源於唐朝詩人賈島的故事,說他爲詩中的「推」「敲」一字之差,反覆思索。數組

Clojure 程序的基礎是函數,函數和使用者惟一的合同是它的參數表,咱們 Clojure 對待它也應該有推敲的精神!函數

不該該有不被引用的參數

這看起來是顯然的,但咱們常常就在反覆改動一個函數實現的時候,忘記檢查它有沒有沒有用的參數。設計

參數要求越簡單精確越好

不要爲了一個值引入整個結構。例如:code

(defn hello [user]
  (str "Hello" (:name user)))

這個函數既然只使用 name ,就不如改爲這樣更精確:ip

(defn hello [name]
  (str "Hello" name))

這個原則的例外在於,有時爲了連續調用,咱們須要一些參數的統一性。這時可使用 destructure 這個強大的語言特性來明示咱們的需求:io

(defn hello [{name :name}]
  (str "Hello" name))

這樣的調用形式既能夠知足要求,也更爲精確地說明了咱們須要的不是一個特別的 user 的 map,而僅僅是一個有 :name 值的 map。class

儘量避免「過路參數」

所謂「過路參數」:函數對參數值不感興趣,把他放進參數表僅僅爲了調用其餘函數。這樣的參數在程序中很常見,例如上例中的函數實際就僅僅是 str 函數的包裝。即便 name 參數都是過路參數,其實,第二個函數定義寫成這樣:基礎

(def hello (partial str "Hello"))

根本不引入一個額外的參數表更加精確。而最後一種形式寫成:cli

(def hello (comp (partial str "Hello") :name))

用函數組合來代替新建函數更爲合適。clojure

固然,這條規則實際上用在 hello 這麼簡單的函數上缺少說明性,咱們用任何一種寫法都很容易理解。但是在實際的工做中,隨意引入過路參數卻會嚴重影響咱們的大設計。

(defn order-description [{:keys [amount]} username]
  (let [client-type (if (> amount 10000) "big" "small"]
    (str (call-name username) " is a " client-type " client."))) 

(order-description {:amount 15000} "Robert")

這個函數中的 username 又是一個過路參數,它在參數表中出現,將咱們函數實際上僅僅關心 call-name 的結果的邏輯掩蓋了起來,而且還形成了咱們對 call-name 這個函數的依賴。改爲這樣:

(defn order-description [{:keys [amount]} call-name]
  (let [client-type (if (> amount 10000) "big" "small"]
    (str call-name " is a " client-type " client.")))

(order-description {:amount 15000} (call-name "Robert"))

就將 call-name 的調用責任放在了它的調用者,讓 order-description 函數的使用範圍更廣和更加穩定。

相關文章
相關標籤/搜索