[Groovy] 程式設計教學:使用控制結構 (Control Structures)

【分享本文】
Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

    控制結構 (control structures) 是用來改變程式運行的順序,讓程式有一些基本的判斷功能。控制結構包括選擇 (selection) 和迭代 (iteration) 兩種;本文介紹 Groovy 中可用的控制結構。Groovy 官網設明文件並未強調控制結構的使用,不過 Groovy 的官方教材 Groovy In Action, 2nd Edition, Manning 中的確有提到一些相關的內容。本文由筆者自行整理而成。

    if

    if 是最基礎的選擇結構,Groovy 承襲 Java,if 的使用方法也相同。if 的虛擬碼如下:

    if (condition) {
        // Run code here.
    }
    

    condition 為真時,會執行 if 區塊內的程式碼。

    我們還可以加上反向的 else 敘述,其虛擬碼如下:

    if (condition) {
        // Run code here if `condition` is true
    }
    else {
        // Run code here if `condition` is false
    }
    

    condition 為真時,執行 if 區塊內的程式碼。反之,則執行 else 區塊內的程式碼。

    除了二元條件外,還可以加上多個 else if 區塊,就可以形成多元條件敘述,參考以下虛擬碼:

    if (condition_1) {
        // Do something_1
    } else if (condition_2) {
        // Do something_2
    } else {
        // Do something else
    }
    

    以本例來說,若符合 condition_1 時,程式會執行 something_1,然後跳出整個 if 區塊。若 condition_1 不符時,程式會試著檢查 condition_2,若符合 condition_2,程式會執行 something_2 後跳出整個區塊。若上述條件皆不符合,程式會執行 else 區塊內的內容。

    if 敘述中,if 是必需的,而 else ifelse 是選擇性的。else if 可以一至多個,而 else 只能有一個,且要放在最後一個區塊。從語義上去想即可,不用死背這個規則。

    以下是簡短的範例:

    final random = new Random()
    final n = Math.abs(random.nextInt() % 3) - 1
    
    if (n > 0) {
        println "n is larger than zero"
    } else if (n < 0) {
        println "n is smaller than zero"
    } else {
        println "n is equal to zero"
    }

    我們先建立一個 random 物件,再由該物件產生一個介於 -11 之間的隨機整數 n。由 n 的值來印出不同的敘述,藉由 if 來進行相關的判斷。

    switch

    switch 算是 if 的語法糖,在 C 家族的語言都會放。其虛擬碼如下:

    switch (value) {
    case a:
        // Do something_a
        break
    case b:
        // Do something_b
        break
    case c:
        // Do something_c
        break
    default:
        // Do something else
    }
    

    同樣也是會依序由上而下檢查,符合特定區塊時則進入該區塊。

    switch 的雷就是會忘了放 break,敘述就會繼續執行下去,這個特性稱為 *fallthrough*。Groovy 為了保留 Java 的習慣,並沒有改掉這項特性,程式設計者需自行注意。

    參考範例如下:

    final now = new Date()
    final c = Calendar.getInstance();
    c.setTime(now);
    final day = c.get(Calendar.DAY_OF_WEEK);
    
    switch (day) {
        case 6:
        case 7:
            println "Weekend"
            break
        case 5:
            println "Thanks God. It's Friday"
            break
        case 3:
            println "Hump day"
            break
        default:
            println "Week"
            break
    }

    在本程式中,我們建立 now 物件,代表當下的時間。接著,從 Calendar 中相關的函式得到 day (day of week)。根據 day 的狀態來印出相對應的訊息,藉由 switch 來進行判斷。

    switchif 可代換,讀者可自行嘗試將本節範例用 if 改寫。

    while

    while 是基本的迴圈 (loop) 語法之一,主要用於以條件句為終止條件的迴圈。其虛擬碼如下:

    while (condition) {
        // Run code here repeatedly while `condition` is true
    }
    

    只要 condition 為真,while 區塊內的程式碼就會重覆執行。

    參考簡短範例如下:

    def i = 10
    
    while (i > 0) {
        println "Count down ${i}"
        i--
    }

    以下是無窮迴圈 (infinite loop):

    while (true) {
        // Run code here repeated indifintely.
    }
    

    如同其名,無窮迴圈內的程式碼區塊會不斷地執行。除了新手偶爾寫錯造成無限迴圈外,實務上我們會用一些中止條件去改變迴圈的行進,詳見下文。

    for

    for 有多種使用方式,一種是使用計數器 (counter) 來走訪,一種是使用迭代器 (iterator);在 Groovy 中,兩種方式都可以。

    傳統的 C 風格 for 使用計數器,參考下例:

    for (def i = 10; i > 0; i--) {
        println "Count down ${i}"
    }

    Groovy 提供 range 語法,可做為迭代器,參考下例:

    for (i in 1..10) {
        assert 1 <= i && i <= 10
    }

    也可以用陣列等容器做為迭代器,詳見後文。

    迭代器 (Iterator)

    迭代器是指等效於迴圈的語句,主要的好處是不需知道迭代器內部的實作,也不需要使用額外的計數器。Groovy 的迭代器可用容器 (collections) 和 closure 走訪,很大一部分是向 Ruby 致敬。

    以下的迭代器指定走訪區塊 3 次:

    3.times { println "Hello World" }

    以下的迭代器走訪一個 range:

    (1..10).each { i -> println i }

    以下的迭代器走訪一個陣列,並附帶索引:

    ["a", "b", "c"].eachWithIndex { e, i ->
        println "${i}: ${e}"
    }

    一開始寫程式時,通常會不太習慣迭代器,而會想用傳統的 forwhile 迴圈;使用那種方式來迭代其實都可以。一開始可以先用傳統的迴圈來寫,寫一段時間後再慢慢把程式碼改寫 (重構) 成迭代器即可。

    continuebreak 改變迴圈行進

    continue 可在迴圈進行到中途時,跳過某一次迭代。參考下例:

    for (def i = 1; i <= 10; i++) {
        if (i % 2 != 0) {
            continue
        }
        
        println i
    }

    這個程式在輪到奇時數會跳過剩下的程式碼,故只會印出偶數。

    break 則可以中斷迴圈。參考下例:

    for (def i = 1; i <= 10; i++) {
        if (i > 5) {
            break
        }
        
        println i
    }

    這個程式在 i6 時迴圈會中斷,故只印出 15

    【分享本文】
    Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email
    【追蹤新文章】
    Facebook Twitter Plurk
    標籤: GROOVY, JAVA