Clojure
零基礎(chǔ)
學(xué)習(xí)筆記
條件語句
分支控制
順序結(jié)構(gòu)、循環(huán)結(jié)構(gòu)讨便、分支結(jié)構(gòu) --- 程序的三大結(jié)構(gòu)
條件控制是一種基本的需求置济,我們經(jīng)常能遇見需要針對(duì)不同內(nèi)容進(jìn)行特定處理的情況。這次我們就來看一下 Clojure 中幾種常見的條件分支鲫剿。
首先看一下最基本的 if
:
=> (if true
1
0)
1
不難看出银室,if
接受三個(gè)參數(shù)涂佃,第一個(gè)參數(shù)是一個(gè)布爾值,如果第一個(gè)參數(shù)為 true蜈敢,則 if
的值就是第二個(gè)參數(shù)的值辜荠;如果第一個(gè)參數(shù)為 false,則 if
的值就是第三個(gè)參數(shù)的值抓狭。很簡單伯病。
不過這里特別說明一個(gè)細(xì)節(jié),Clojure 中所有的表達(dá)式都有值否过。if
也不例外午笛,它也有值。if
的值是由它第一個(gè)參數(shù)的真假所決定的叠纹,這也是它稱為條件結(jié)構(gòu)的原因季研。這使得你可以用統(tǒng)一的編程思想去寫 Clojure 代碼敞葛,把表達(dá)式作為一個(gè)值誉察,放在你需要的任何位置,繼續(xù)作為一個(gè)值來代入下一步計(jì)算惹谐。
相反的持偏,在其它很多語言里,并不是所有的式子都有值氨肌。如果你曾學(xué)習(xí)過 C鸿秆、Java 等語言,會(huì)發(fā)現(xiàn) if 語句本身并沒有值怎囚,僅僅起到控制程序走向的功能卿叽。Clojure 中的 if
反而更像 C、Java 里的三元運(yùn)算式恳守。
我們?cè)囍鴮懸粋€(gè)函數(shù)來做這樣的事情:傳入一個(gè)整數(shù)考婴,打印這個(gè)數(shù)字是奇數(shù)還是偶數(shù)。
=> (defn odd-or-even
[num]
(if (= (mod num 2) 0)
(println num "是偶數(shù)")
(println num "是奇數(shù)")))
#'user/odd-or-even
=> (odd-or-even 1024)
1024 是偶數(shù)
nil
這里可以觀察到催烘,由于 (= (mod num 2) 0)
的值為 true沥阱,所以執(zhí)行了 (println num "是偶數(shù)")
,但是 println
的值為 nil伊群,所以 if
的值也就變成了 nil考杉。
這里有個(gè)小問題策精,如果傳入的是一個(gè)小數(shù),我們的程序會(huì)錯(cuò)誤的認(rèn)為它是一個(gè)奇數(shù)崇棠。
Clojure 本身提供了一個(gè)返回布爾型的函數(shù) even?
用來判斷一個(gè)數(shù)字是不是偶數(shù)咽袜,如果是偶數(shù)則返回 true,不是偶數(shù)則返回 false枕稀。所以我們也可以這么寫:
(defn odd-or-even
[num]
(if (even? num)
(println num "是偶數(shù)")
(println num "是奇數(shù)")))
這樣如果你傳入一個(gè)小數(shù)酬蹋,它就會(huì)報(bào)錯(cuò)提示你 “參數(shù)必須是整數(shù)”。
Clojure 還提供了一個(gè) if-not
函數(shù)抽莱,用來做和 if
完全相反的事情范抓。
如果遇見更為復(fù)雜的問題,比如判斷考試成績的優(yōu)良中差食铐,當(dāng)然匕垫,你可以通過嵌套多層 if
來處理。不過 Clojure 提供了另外一個(gè)方便多層次判斷的東西 --- cond
虐呻。
我們來看看如何使用 cond
來解決判斷成績優(yōu)良中差的問題象泵。
=> (defn rating
[score]
(cond
(>= score 90) "優(yōu)秀",
(>= score 80) "良好",
(>= score 70) "中等",
(>= score 60) "及格",
(< score 60) "較差",))
#'user/rating
=> (println (rating 78))
中等
nil
由上面的例子我們可以總結(jié)出 cond
的用法,它接受若干對(duì)參數(shù)斟叼,每一對(duì)參數(shù)分別是布爾型的表達(dá)式和另一個(gè)表達(dá)式偶惠。cond
會(huì)由上至下的判斷每個(gè)布爾表達(dá)式,一旦判斷為 true朗涩,則 cond
的值就會(huì)變成判斷為 true 后面所跟表達(dá)式的值忽孽。如果判斷到末尾依然沒有任何表達(dá)為 true,則 cond
的值等于 nil 谢床。
注意兄一,一旦 cond
發(fā)現(xiàn) true,會(huì)停止繼續(xù)解析下面的式子识腿,所以如果式子的先后順序出現(xiàn)問題就會(huì)出現(xiàn)意外:
=> (defn rating
[score]
(cond
(>= score 60) "及格",
(>= score 90) "優(yōu)秀",
(>= score 80) "良好",
(>= score 70) "中等",
(< score 60) "較差",))
#'user/rating
=> (println (rating 98))
及格
nil
你還可以提供一個(gè) :default
值來確保沒有任何匹配時(shí)出革,返回你所設(shè)置的默認(rèn)值:
=> (defn rating
[score]
(cond
(>= score 90) "優(yōu)秀",
(>= score 80) "良好",
(>= score 70) "中等",
(>= score 60) "及格",
:default "較差",))
#'user/rating
=> (println (rating -10))
較差
nil
有些時(shí)候我們需要處理一些固定有限的情況,比如把阿拉伯?dāng)?shù)字轉(zhuǎn)換成中文大寫數(shù)字渡讼,處理一些狀態(tài)碼骂束,等。
這個(gè)時(shí)候 case
是最佳選擇成箫。(相當(dāng)于 C / Java 等語言中的 switch
)
=> (defn arabic-num-to-chinese-num
[arabic-num]
(case arabic-num
1 "壹",
2 "貳",
3 "叁",
4 "肆",
5 "伍",
6 "陸",
7 "柒",
8 "捌",
9 "玖",
0 "零",
"未知"))
=> #'user/arabic-num-to-chinese-num
=> (println (arabic-num-to-chinese-num 8))
捌
nil
case
的用法也很簡單直觀展箱,它的第一個(gè)參數(shù)是一個(gè)表達(dá)式,余下參數(shù)是一些鍵值對(duì)伟众。在這些鍵值對(duì)中析藕,首先尋找第一個(gè)參數(shù)的值所對(duì)應(yīng)的鍵,case
的值就等于我們找到的鍵所對(duì)應(yīng)的值。需要注意账胧,如果出現(xiàn)找不到匹配的情況竞慢,case
不會(huì)返回 nil,而是會(huì)報(bào)錯(cuò)治泥。所以我們需要在最后一行加上一個(gè)默認(rèn)值筹煮,就如同上面例子中的 "未知"
。一旦出現(xiàn)無法匹配的情況居夹,case
的值就是我們所設(shè)定的默認(rèn)值败潦。
需要特別注意的是,case
中所接受的鍵值對(duì)中的 鍵准脂,一定是直接寫出的常量劫扒,而不能是需要計(jì)算才能得出值的表達(dá)式。