## 条件处理
`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")))
```