- 用Flutter極速構建原生應用
- 張益琿
- 3554字
- 2020-01-20 15:01:05
2.5 Dart中的流程控制語句
流程控制是一個程序的靈魂,之前我們編寫的代碼都是順序執行的,即代碼從上到下一行一行地依次執行。在實際開發中,這種順序執行的程序少之又少,我們往往需要結合使用分支語句、循環語句、中斷語句等來實現復雜的邏輯。本節將介紹Dart中常用的一些流程控制語句,使用這些語句可以編寫出功能更加靈活強大的Dart程序。
2.5.1 條件分支語句
條件分支語句是Dart中分支語句的一種,當被判定的值或者表達式符合某個條件時,才執行預定的邏輯代碼。和許多編程語言類似,Dart中也使用if-else結構作為條件分支語句。示例代碼如下:

運行上面的代碼,控制臺將依次輸出字符串“成功”和“程序結束”。如果將res變量的值修改為false,程序就不會執行if語句塊中的代碼,直接執行打印“程序結束”的代碼。
上面演示的if語句首先需要進行條件的判定,條件必須為布爾值或者返回布爾值的表達式,如果條件成立,就會執行其后緊跟的代碼塊,否則跳過此代碼塊。if-else是一種更為常用的條件分支結構,示例如下:

上面的代碼首先會對if后面的條件進行判定,如果條件成立,就執行if后面代碼塊中的代碼,如果不成立,就執行else后面代碼塊的代碼。也就是說,在if-else結構中,總有一個代碼塊會被執行。對應的,還有另一種if-else的變體結構,示例如下:

if-else if-else結構可以進行多級條件判斷,從第一個if判定條件開始,如果條件成立,就直接執行其后的代碼塊,如果不成立,就繼續向后進行下一個if條件的判定,如果所有判定條件都不成立,最終會執行最后的else中的代碼。當然,最后一個else代碼塊可以省略。
一個完整的程序往往需要有和用戶進行交互的能力,和用戶交互實際上就是讓用戶做出選擇,條件語句的作用就是根據用戶的響應來使程序做出不同的反應,實現程序的智能化。
2.5.2 循環語句
和人腦相比,計算機的最大優勢在于其可以非常迅速地完成大量且重復的計算。循環語句的作用就是將某段代碼重復地執行。首先,我們思考一個問題,如何編寫代碼計算1+2+…+100這個算式的值。你可能馬上就能答出來,這不就是一個等差數列求和的問題,使用公式很容易計算出來:

沒錯,這正是人腦相較于計算機最大的優勢,人腦善于總結、歸納以及推導出方法,而計算機則善于循規蹈矩地做重復大量的工作。使用循環語句可以不依賴公式進行大量等差數值求和運算,示例如下:

本小節我們一起來學習Dart中循環語句的用法。
Dart支持4種類型的循環,以上代碼中的while循環是最為簡單的一種,其while關鍵字后面的小括號中需要填入要判定的條件表達式或布爾值變量。當判定為true,即條件成立時,會執行循環體中的代碼塊,當代碼塊執行完成后,程序會回到while條件判定處,再次判定條件是否成立,如果成立,就繼續執行循環體內的代碼塊,如此循環,直到條件不再成立為止。因此,對于while循環結構,一般會在循環體中修改判定條件,否則程序會陷入無限循環,永遠無法跳出while循環結構。
while語句還有一種變種,叫作do-while,它的結構如下:
do{ 循環體 }while(條件);
do-while結構和while結構的區別在于:while語句會首先進行循環條件的判定,如果不滿足,就不再執行循環體,滿足條件才會進行循環;而do-while語句則是首先執行一次循環體中的代碼,之后進行循環條件的判定,如果滿足,就繼續執行循環體,如果不滿足,就跳出循環,例如:

for循環也是一種非常常用的循環結構,并且相對于while循環,for循環的寫法更加簡潔。使用for循環解決同樣的累加問題,示例代碼如下:

for循環的結構如下:

在for關鍵字后的小括號中需要填入3個表達式,其中第1個表達式用來初始化循環變量,這個變量用來控制循環執行的次數;第2個表達式為循環的判定條件,不滿足條件時會跳出循環;第3個表達式會在每次循環體執行結束后執行,一般用來對循環變量進行操作。
很多時候,我們使用循環語句都是用來對集合對象進行遍歷的,例如下面的代碼會將列表中所有的元素依次進行打印:

對于集合類型對象的遍歷,for-in循環是一種更加快速的方式。for-in語句也被稱為迭代語句,專門用來進行集合遍歷,例如:

for-in語句的結構如下:
for(變量 in 集合){ 循環體 }
在for-in語句中,in關鍵字前為對象變量,每次循環后都會將集合中遍歷出的元素賦值給這個變量,in關鍵字后為要進行遍歷的集合,集合中的元素會被依次取出賦值給對象變量,并執行循環體中的代碼。
2.5.3 中斷語句
中斷語句常常與循環語句配合使用,中斷語句的用途是提前中斷循環。對于2.5.2小節的等差數列累加問題,使用下面的代碼也可以很好地解決:

上面的break語句就是中斷語句,當代碼執行到break語句時,會直接跳出當前的循環執行后面的代碼,因此即使我們不對循環的判定條件進行操作,在循環過程中也很容易結束循環。
Dart中還提供了一個很常用的中斷語句:continue語句。break語句會直接跳出本層循環,執行循環后面的代碼,而continue語句則是跳過本次循環后,還會進行循環條件的判定,如果條件依然滿足,就會繼續執行循環。示例代碼如下:

break中斷語句,其也可以在多分支選擇結構中使用,用來命中某個分支后跳出整個結構。在2.5.4小節中,我們會介紹多分支選擇語句的使用。
2.5.4 多分支選擇語句
其實多分支選擇語句可以完成的工作使用if-else語句都可以完成,但是在某些場景下,使用多分支選擇語句switch-case能夠寫出更加整齊規則的代碼。在學習if-else語句時舉過一個小例子,以學生的分數來劃分學生的成績段,代碼如下:

假如現在我們需要把上面代碼的邏輯反過來,根據學生的成績來輸出學生的分數段,使用switch-case語句編寫如下:

運行上面的代碼,將輸出“成績在85分以上”。switch-case語句的作用是用來進行條件的匹配,switch關鍵字后面填寫要進行匹配的變量,之后列舉case語句進行匹配,如果匹配成功,就會執行對應的case代碼塊。需要額外注意,每一個case塊的結尾都需要使用break語句進行中斷,否則運行時會有異常產生。
由于switch-case進行精準的值匹配,要進行匹配的case語句也有限,因此可能會出現所有case語句都沒有匹配的情況,這時會跳過switch-case結構執行后面的代碼,如果需要提供默認的處理邏輯,就可以在switch結構中添加default塊,代碼如下:

上面的代碼所有的case語句都沒有匹配上,這時默認會執行default代碼塊中的代碼。
2.5.5 異常處理
任何代碼都有產生異常的可能,程序的邏輯越復雜、代碼量越大,產生異常的可能性也越大。在編寫代碼時,我們不能強求沒有異常產生,而是要將注意力放在產生異常后的處理工作。
大部分的程序都需要和用戶進行交互,和用戶交互的基礎是接收用戶的操作輸入,而對于用戶的操作開發者往往是不可預料的,因此在編寫代碼時,我們要時刻注意對用戶輸入的數據進行限制,當用戶輸入了錯誤的數據時,讓程序中斷掉。
在編寫代碼時,當我們調用了錯誤的方法或者用錯了變量的類型時,程序會中斷,并將異常信息打印出來。其實,我們也可以自己產生和拋出異常,例如下面的代碼:

假設上面代碼中的變量a為用戶輸入的數據,程序之后會使用這個數據進行后續處理,但是要保證數據a的值大于0。此時,如果發現輸入的a小于0,就使用throw關鍵字拋出異常,運行代碼,控制臺會輸出如下文本:
Unhandled exception: 輸入有誤
上面輸出的意思是產生了未處理的異常,程序提前中斷,并且將異常對象打印了出來。前面拋出的異常對象為字符串“輸入有誤”,其實要拋出的異常對象可以是任意類型的對象。更通用的做法是通過定義異常類來封裝異常,異常類中有具體的異常原因、類型、錯誤碼等信息。
當程序運行到throw拋出異常語句時,會中斷掉,這往往會造成很差的用戶體驗。一個完整的應用程序可能不止一個功能,因為一個小功能的異常而造成整個應用程序無法工作是非常不明智的。在Dart中,提供了對異常進行捕獲的方法,開發者可以選擇對捕獲到的異常進行處理,也可以忽略它,如果進行了異常捕獲,程序就不會中斷。使用try語句進行異常的捕獲,示例代碼如下:

再次運行代碼,可以看到程序完整運行到了最后。
try結構有這樣的特點,首先其后面的代碼塊中需要將可能產生異常的代碼放入,可以是幾行代碼,也可以是函數,等等。如果這些代碼在執行時拋出異常,就會將異常捕獲,并根據異常的類型將其分配入指定的處理模塊。try結構塊后面跟隨的on語句用來指定要捕獲的異常類型,例如,如果拋出的異常是字符串類型的對象,就會進入on String對應的代碼塊繼續執行代碼,這里面我們可以根據實際情況來進行異常的處理,完成后程序會繼續向后執行。如果需要獲取具體的異常對象,就可以使用catch語句來捕獲,示例如下:

運行上面的代碼,將輸出“捕獲了字符串類型的異常:輸入有誤”。catch語句后面的括號中也可以將異常的堆棧信息捕獲到,catch括號后面的第一個參數為異常對象,可以添加第二個參數來獲取堆棧信息,代碼如下:

即使捕獲到異常,開發者也可以根據實際情況決定是處理、忽略還是繼續將異常拋出,如果需要繼續拋出異常,那么使用rethrow關鍵字即可,對于函數在嵌套調用中產生的異常,常常會用這個關鍵字來傳遞異常。rethrow的示例代碼如下:

try-catch結構的最后還可以追加一個finally塊,finally塊的作用是無論異常是否產生,也無論是否捕獲,最終都會執行該代碼,例如:

finally塊通常用來執行數據清理相關操作。
- Mastering JavaScript Functional Programming
- 工程軟件開發技術基礎
- Java EE框架整合開發入門到實戰:Spring+Spring MVC+MyBatis(微課版)
- Manga Studio Ex 5 Cookbook
- Python Geospatial Development(Second Edition)
- .NET 3.5編程
- HTML5 APP開發從入門到精通(微課精編版)
- Mastering Python Design Patterns
- 代替VBA!用Python輕松實現Excel編程
- QGIS 2 Cookbook
- 軟件工程與UML案例解析(第三版)
- 大學計算機應用基礎(Windows 7+Office 2010)(IC3)
- C# 7.1 and .NET Core 2.0:Modern Cross-Platform Development(Third Edition)
- Neo4j 3.x入門經典
- SQL Server 2014 Development Essentials