推敲你的函数参数表

“推敲”这个词来源于唐朝诗人贾岛的故事,说他为诗中的“推”“敲”一字之差,反复思索。数组

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 函数的使用范围更广和更加稳定。

相关文章
相关标签/搜索