如今咱們首先定義一個支持4個參數相加的函數:java
(defn add [ v1 v2 v3 v4] (+ v1 v2 (if v3 v3 0) (if v4 v4 0) ))
咱們想達到這樣一種效果。若是咱們調用(add 1 2 3 4),則正常返回10。若是咱們調用(add 1 2 3)能獲得結果6。或者調用(add 1 2)能獲得3。express
咱們執行後發現:數組
=> (add 1 2 3 4) 10 => (add 1 2) ... ArityException Wrong number of args (2) passed to: user$add ...
當參數數量和咱們定義函數時的參數數量一致時能獲得正確的值。不然會拋出參數數量不匹配異常。看來這個和咱們預想的不同啊。函數
咱們以前定義函數時,使用的都是固定參數方式。調用函數時,只要咱們傳入參數的數量不符合定義時的參數數量,clojure都會提出抗議(拋出參數數量不匹配異常)。像上面咱們能夠這麼調用(add 1 2 3 nil),這樣會返回6。 (if v4 v4 0)的含義是,若是v4 不爲nil或false,就返回v4,不然返回0。咱們傳入的正是nil。因此函數會正確返回6。固然(add 1 2 nil nil )也會正確返回3。spa
難道clojure就這麼點能力?固然不是,clojure的固定參數可不止這點能耐。咱們在上篇列出的定義函數時的腳手架其實並無列完整。請看下面一個更加完整的腳手架:code
(defn variable-name "description" {metadata} ([argument-pattern #1] ;;第一種參數形式 body-of-expressions) ([argument-pattern #2] ;;第二種參數形式 body-of-expressions) more-patterns... )
先讓咱們用上面方式重構一下以前的add函數,看看怎麼來支持2個、3個或4個參數的相加:ip
(defn add ( [v1 v2] ( + v1 v2)) ( [v1 v2 v3] (+ v1 v2 v3)) ( [v1 v2 v3 v4] (+ v1 v2 v3 v4)) )
上面咱們總共定義了三種不一樣參數形式的add函數。這樣調用的話(add 1 2)會匹配第一種形式,正確返回3。(add 1 2 3)會匹配第二種參數模式,返回結果6。這其實就是lisp中模式匹配的一種應用。是否是比java中的重載方式更加靈活呀。這只是固定參數的一種用法,下面再來看看clojure的可變參數用法。it
若是咱們的參數模式就兩三種(例如上面只須要支持3種不一樣個數的數字相加),咱們能夠採用固定參數+模式匹配來實現函數。可是若是咱們的參數模式個數不固定(例如支持任意個數字相加),固定參數+模式匹配也拯救不了咱們了。不過不用擔憂,clojure還給咱們提供了可變參數 。io
咱們看一下如何使用可變參數來實現任意個數的數字相加:class
(defn add [v1 v2 & others] ;;&後面的是可變參數 (+ v1 v2 (if others ;;判斷可變參數列表是不是空,若是不是累加列表中的值,不然返回0 (reduce + 0 others) ;;使用reduce函數計算others的數字之和。 0 ) ) )
這裏有幾點須要注意一下,固定參數要寫在一個「&」以後,只能有一個可變參數。&後的可變參數名錶明的是由可變參數組成的列表。這裏的reduce函數,先理解成對列表中的數字進行累加就行,本文目的主要是理解可變參數的用法。
如今咱們執行一下上面定義的函數:
=> (add 1 2) 3 => (add 1 2 3) 6 => (add 1 2 3 4 5 6) 21
如今add已經支持任意個數字參數相加了。