第 15 講:程序結構(一):條件結構
我們前面用了六個文章介紹了運算符的使用。今天我們進入新的板塊:程序控制結構。C 語言里,程序控制結構一共有四種:順序結構、條件結構、循環(huán)結構和跳轉結構。C# 里一共是 5 種:順序結構、條件結構、循環(huán)結構、跳轉結構和異??刂平Y構。順序結構是最基礎的結構,在前面的文章早就體現(xiàn)過了,只是沒有提出它的名稱。只要一段代碼從上到下依次執(zhí)行的過程,我們就把這段代碼稱為順序結構。
Part 1 if
的用法
1-1 if
語句
前面的內(nèi)容我們無法控制代碼在指定條件的時候,才做一些工作。當我們需要這樣的用法的話,我們將使用 if
語句來控制。
格式是這樣的:
有這樣兩種寫法。我們來寫一個例子。
在這個例子里,我們在 if (a > b)
之后使用大括號,將 Console.WriteLine
完整包裹起來。這表示,用大括號包裹起來的所有內(nèi)容,都屬于“當 a > b
成立的時候,才會執(zhí)行的邏輯”。
當 a > b
的結果是 false
(即不成立)的時候,不管大括號里有多少東西,都不會得到執(zhí)行,會被完全忽視掉。顯然,這個例子里,30 是比 40 小的,所以條件并不成立。因此,你在執(zhí)行過程之中,什么輸出都看不到。
順帶一說,既然用到了大括號,那么里面的內(nèi)容就需要縮進來保證代碼的整潔。如果大括號內(nèi)的內(nèi)容不縮進的話,看起來就很奇怪。當然,它并不影響編譯程序和運行程序就是了。
1-2 else
語句
顯然,這樣的格式并不能滿足我們正常的需求。前文的例子我們其實還想看到另外一個輸出內(nèi)容,“b
比 a
大”,但在代碼里沒有體現(xiàn)。因此,else
就派上用場了。
和 if
差不多,else
后也是跟一個大括號,或者一個單獨的語句。這部分表示在 if
條件并不成立的時候,才會得到執(zhí)行。
如果我們這么寫代碼的話,這就表示,當 if (a > b)
里的 a > b
條件成立的時候,會輸出 a
比 b
大的內(nèi)容;但是如果不成立,就會輸出 b
大于 a
的內(nèi)容。
if
-else
整體的話,if
的部分和 else
的部分并不會都執(zhí)行,也必然必須執(zhí)行至少一個部分。這就是 if
-else
配合一起使用的時候的特點。
當然,前文說過,空格是不影響編譯和運行程序的,因此我們甚至可以寫在一行:
這么寫依然是沒有問題的。代碼寫成什么樣看的是個人的習慣,只要邏輯沒有問題就行。
1-3 else
后也不一定非得是大括號和語句
a > b
的對立情況就一定是 b > a
嗎?當然不是,還可以相等。但是我們剛才沒有體現(xiàn)這一點。下面我們來試著添加這個部分:
當 a > b
條件不成立的時候,我們會想著走 else
這一段代碼。而 else
里又是一個 if
判斷:a == b
a > b
條件是不是成立的。如果不成立,就會繼續(xù)判斷 a == b
這個條件。因此,實際上這種寫法就解決了前面說的,忘記判斷 a == b
的問題。
不過,這個寫法還是有點丑。C# 可以允許我們?nèi)サ?else
的大括號:
這個寫法是沒有問題的。C# 是知道,下方的 if
-else
是一個整體,因此不需要大括號就知道整個代碼里的 else
就完整包含了下面一大坨內(nèi)容。但是,實際上還是有點丑。不如我們把 else
后直接跟上 if
:
這樣就很好了。從這個角度來說,我們一下就可以看出邏輯:先 a > b
;如果不滿足就 a == b
;再不滿足就執(zhí)行最下面的 else
1-4 它和條件運算符的關聯(lián)
最開始,我們說到過一個東西,叫條件運算符。條件運算符的邏輯完全類似于這里的 if
-else
的過程。不過問題在于,它們有區(qū)別嗎?
條件運算符用來表示和賦值,因此 ?
后和 :
后的部分全都是一個表達式(所謂的表達式,就必須反饋一個結果數(shù)值出來;而語句則不一定要反饋結果,它可以像是 Console.WriteLine
那樣,單獨成一個語句來用)。而 if
-else
則可以跟語句或者是賦值表達式。我們來看一下。
這是將 a
和 b
較大的數(shù)值賦值給 c
的過程。如果要寫成 if
-else
,就得這樣:
或者直接寫到一行上去:
不管怎么做,代碼都比條件運算符要復雜。因此,我們建議用條件運算符而不是用 if
-else
1-5 永真和永假條件
有沒有想過,既然這里我們傳入的是一個 bool
的表達式,那么我們直接寫 true
和 false
會如何。
或者
猜都猜得到,只要條件是 true
就會進去執(zhí)行。因此 if (true)
等價于根本沒寫條件判斷。而 if (false)
if
里面的語句永遠都得不到執(zhí)行。
Part 2 switch
的用法
很顯然,前文的 if
-else
是無敵的。但是很遺憾的是,對于一些特殊的條件判斷,if
-else
怎么寫都很臃腫。比如我們輸入一個月份數(shù)值,然后判斷月份到底有多少天。那么用 if
就得這樣:
我且不說其它的內(nèi)容,就判斷 month
的信息,也顯得很臃腫。此時,我們這里介紹一個新的語法格式:switch
語句。
2-1 switch
語句
switch
語句的用法是這樣的:
這個寫法可能不是很好懂。我們直接上代碼:
貌似……好像代碼沒有減少多少。不過更好看了,因為 month
直接寫到 switch
上用來表示“我這里就是按 month
case
里寫的就是 month
的所有可能數(shù)值。default
則表示當前面所有數(shù)值都不是 month
現(xiàn)在的數(shù)值的時候,就走這里。
請注意一下,每一個 case
語句最后,都要跟一個 break;
,這是因為這是為了讓每一個 case
斷層。C 語言里,沒有寫 break
就會導致執(zhí)行的時候出現(xiàn)潛在的問題。C# 沿用了這種機制,但防止你誤用代碼,所以不寫 break
會產(chǎn)生編譯錯誤,提示你必須加了 break;
之后才能繼續(xù)執(zhí)行。C# 里,break;
語句遇到后,會自動跳出 switch
的內(nèi)容。比如這個例子里,會自動跳轉到第 27 行代碼執(zhí)行。
2-2 同執(zhí)行語句簡化
顯然,我們發(fā)現(xiàn)當 1、3、5、7、8、10、12 月份的時候,day
都是 31;而當 4、6、9、11 的時候,day
都是 30。switch
還有一個強勁的功能就是,簡化 case
。我們只看 switch
這一塊,代碼可以簡化成這樣:
這樣的話,就更簡單一些了。如果寫 if
||
來連接條件。比如說第 3 行轉成 if
就得寫成這樣:
顯然,就很丑。
2-3 字符串的 switch
在 C# 里,因為有字符串這種類型,因此 switch
還可以對字符串進行判斷。
case 字符串
的格式。確實,C# 也是允許這么做的。
由于字符串的每一個字符都不一樣的關系,就算只有大小寫不同的兩個字符串也屬于兩個不同的字符串,因此我們這里在例子程序中是分開成兩個情況作判斷的。
2-4 很遺憾,布爾量沒有 switch
這顯然是廢話。bool
類型的數(shù)值往往只有 true
和 false
兩種可選情況,那么你要寫成 switch
語句的話,你只能寫成這樣:
可問題在于,case true
和 case false
就已經(jīng)構成了 bool
類型的所有可能取值的情況。那么,我是不是就意味著我可以把這里的 case false
替代為 default
呢?那么,我這么寫和前文的語義是一樣的嗎?
如果真的是一樣的,那么我這么寫代碼不就很奇怪了嗎?
是的??紤]到這種寫法的語義格式的復雜性,以及使用場景的問題,C# 并未對布爾型變量開放允許使用 switch
語句。雖然很遺憾,但也是合情合理的情況。
Part 3 混用 switch
和 if
前文我們沒有判斷 2 月份在平年還是閏年。如果我們加上這個判斷的話,就這么寫:
case
最后必須跟一個 break;
,因此就算我們寫了一大坨東西,最后的 break;
也是不可少的。當然了,你也可以這么寫:
這么寫呢,就是長一點,但是用的是條件運算符。
Part 4 if
和 switch
的選擇
如果你在寫代碼的時候,肯定會遇到“我到底用 if
好,還是 switch
好”的問題。有一個很好的判斷標準是,。
比如前面的例子,我們對 month
進行數(shù)值的確認,顯然是用 switch
更合理;但是如果是其它的情況,我們都應該采用 if
來表示。當然了,如果可能數(shù)值過多的話,我們就不建議用 switch
了。