前幾章中,咱們用了一種比較迂迴的方式建立函數:把匿名函數綁定到一個變量上。實際上,clojure提供了一個更好的方式作同一件事情。「defn」 這個函數就是專門用於定義函數的。 java
在咱們使用defn以前,咱們再回顧一下以前咱們怎麼使用def來建立函數的,而後咱們使用defn來作同一件事情對比一下。 shell
;;使用def =>(def alphabet-length (fn [ ](count alphabet))) #'user/alphabet-length =>(alphabet-length) 26 ;;使用defn =>(defn alphabet-length [ ](count alphabet)) #'user/alphabet-length =>(alphabet-length) 26上面兩種方式作的都是同一件事情。可是defn能作更多的事情。下面是defn定義函數的一個腳手架:
[1] (defn name 函數名 [2] "description" 函數描述 (可選) [3] {metadata} 元數據 (可選) [4] [arguments] 參數列表 [5] body-of-expressions...) 函數體上面咱們能夠看出,defn在定義函數時能夠提供更多的信息。
下面讓咱們用上面這些信息定義一個函數: express
=>(defn select-random "從一個列表中隨機返回一個元素" {:added "1.2"} ;; 元數據 [options] (nth options (rand-int (count options)))) #'user/select-random
(count options) 用於計算options包含的元素數量。(nth options x) 用於從options中獲取第x個元素(從0開始,相似java中的list的get方法) 編程
咱們以前說過clojure是lisp的一種方言。lisp 是 「List Processor」的縮寫,就是列表解析的意思,使用列表來表示全部的東西(S表達式)。從咱們寫的代碼也能夠看出,整個代碼結構就是一個嵌套的列表。如今讓咱們用列表結構來保存數據: app
=>(list "growl" "lick" "jump") ("growl" "lick" "jump")咱們以前定義的函數select-random須要的參數正是一個列表,正好咱們就能夠用來測試:
=>(select-random (list "growl" "lick" "jump")) "jump" =>(select-random (list "growl" "lick" "jump")) "growl"運行一切正常,說明select-random沒什麼問題。咱們能夠在一個新的函數中來使用它。咱們來建立一個用於問候的函數greeting。
=>(defn greeting "Composes a greeting sentence. Expects both the name of a greeter and the name of whom is to be greeted for arguments. An approach and an action are randomly selected." {:added "1.2"} [greeter whom] ;;str 用於組裝字符串 (str greeter " greeted " whom " with a " (select-random (list "ferocious" "wimpy" "precarious" "subtle")) " " (select-random (list "growl" "lick" "jump")) "!")) #'user/greeting =>(greeting "Jon" "Thaddeus") "Jon greeted Thaddeus with a wimpy growl!" =>(greeting "Jon" "Thaddeus") "Jon greeted Thaddeus with a precarious lick!"
固然,上面的問候函數不是很完美。咱們能夠把問候語句單獨提出來。 dom
=>(def approaches (list "ferocious" "wimpy" "precarious" "subtle")) 'user/approaches =>(def actions (list "growl" "lick" "jump")) #'user/actions而後在greeting中使用綁定的列表:
=>(defn greeting "Composes a greeting sentence. Expects both the name of a greeter and the name of whom is to be greeted for arguments. An approach and an action are randomly selected." {:added "1.2"} [greeter whom] (str greeter " greeted " whom " with a " (select-random approaches) " " (select-random actions) "!")) #'user/greeting如今可讀性好多了吧,把變化的部分單獨抽象出來這個原則對於函數式編程也是通用的哦。這樣咱們就能夠在不修改函數的狀況下改變問候語句了。
至於函數定義中的元數據有什麼做用,暫時保密,後面會單獨來說。 函數式編程