【在主画面加入捷径】
       
【选择语系】
繁中 简中

[Groovy] 程序设计教学:使用控制结构 (Control Structures)

    控制结构 (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

    TAGS: GROOVY, JAVA