## 條件處理
`if` 這個special form跟java里面的if的語義是一樣的, 它接受三個參數, 第一個是需要判斷的條件,第二個表達式是條件成立的時候要執行的表達式,第三個參數是可選的,在條件不成立的時候執行。如果需要執行多個表達式,那么把多個表達式包在do里面。看例子:
```
(import '(java.util Calendar GregorianCalendar))
(let [gc (GregorianCalendar.)
day-of-week (.get gc Calendar/DAY_OF_WEEK)
is-weekend (or (= day-of-week Calendar/SATURDAY) (= day-of-week Calendar/SUNDAY))]
(if is-weekend
(println "play")
(do (println "work")
(println "sleep"))))
```
宏 `when` 和 `when-not` 提供和if類似的功能, 只是它們只在條件成立(或者不成立)時候執行一個表達式。另一個不同是,你可以執行任意數目的表達式而不用用do把他們包起來。
```
(when is-weekend (println "play"))
(when-not is-weekend (println "work") (println "sleep"))
```
宏 `if-let` 把一個值bind到一個變量,然后根據這個binding的值來決定到底執行哪個表達式。下面的代碼會打印隊列里面第一個等待的人的名字,或者打印“no waiting”如果隊列里面沒有人的話。
```
(defn process-next [waiting-line]
(if-let [name (first waiting-line)]
(println name "is next")
(println "no waiting")))
(process-next '("Jeremy" "Amanda" "Tami")) ; -> Jeremy is next
(process-next '()) ; -> no waiting
```
`when-let` 宏跟 `if-let` 類似, 不同之處跟上面 `if` 和 `when` 的不同之處是類似的。 他們沒有else部分,同時還支持執行任意多個表達式。比如:
```
(defn summarize
"prints the first item in a collection
followed by a period for each remaining item"
[coll]
; Execute the when-let body only if the collection isn't empty.
(when-let [head (first coll)]
(print head)
; Below, dec subtracts one (decrements) from
; the number of items in the collection.
(dotimes [_ (dec (count coll))] (print \.))
(println)))
(summarize ["Moe" "Larry" "Curly"]) ; -> Moe..
(summarize []) ; -> no output
```
`condp` 宏跟其他語言里面的switch/case語句差不多。它接受兩個參數,一個謂詞參數 (通常是 `=` 或者 `instance?` ) 以及一個表達式作為第二個參數。在這之后,它接受任意數量的值-表達式的對子,這些對子會按順序evaluate。如果謂詞的條件跟某個值匹配了, 那么對應的表達式就被執行。一個可選的最后一個參數可以指定, 這個參數指定如果一個條件都不符合的話, 那么就返回這個值。如果這個值沒有指定,而且沒有一個條件符合謂詞, 那么一個 `IllegalArgumentException` 異常就會被拋出。
下面的例子讓用戶輸入一個數字,如果用戶輸入的數字是1,2,3,那么程序會打印這些數字對應的英文單詞。否則它會打印”unexpected value”。在那之后,它會測試一個本地binding的類型,如果是個數字它會打印這個數字乘以2的結果;如果是字符串, 那么打印這個字符串的長度乘以2的結果。
```
(print "Enter a number: ") (flush) ; stays in a buffer otherwise
(let [reader (java.io.BufferedReader. *in*) ; stdin
line (.readLine reader)
value (try
(Integer/parseInt line)
(catch NumberFormatException e line))] ; use string value if not integer
(println
(condp = value
1 "one"
2 "two"
3 "three"
(str "unexpected value, \"" value \")))
(println
(condp instance? value
Number (* value 2)
String (* (count value) 2))))
```
`cond` 宏接受任意個 謂詞/結果表達式 的組合。它按照順序來測試所有的謂詞,直到有一個謂詞的測試結果是true, 那么它返回其所對應的結果。如果沒有一個謂詞的測試結果是true, 那么會拋出一個 `IllegalArgumentException` 異常。通常最后一個謂詞一般都是true, 以充當默認情況。
下面的例子讓用戶輸入水的溫度, 然后打印出水的狀態: 是凍住了,還是燒開了,還是一般狀態。
```
(print "Enter water temperature in Celsius: ") (flush)
(let [reader (java.io.BufferedReader. *in*)
line (.readLine reader)
temperature (try
(Float/parseFloat line)
(catch NumberFormatException e line))] ; use string value if not float
(println
(cond
(instance? String temperature) "invalid temperature"
(<= temperature 0) "freezing"
(>= temperature 100) "boiling"
true "neither")))
```