位元詩人 [Groovy] 程式設計教學:使用閉包 (Closure)

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

前言

在 Groovy 中,最接近函式的東西是閉包 (closure)。基本上,可以把 Groovy 的閉包當成類似其他語言的匿名函式 (anonymous function) 來看待。在先前的文章中,我們其實已經看過閉包了,因 Groovy 中大量使用閉包,像是看起來很像 Ruby 語法的迭代器、串列操作、映射操作等基本上內部皆以閉包來運作。

建立閉包

以下範例建立一個最簡單的閉包:

// Declare a closure.
def hello = { println "Hello World" }

// Call the hello closure.
hello()

// Alternatively, explicit call
hello.call()

在這個範例的閉包,既沒有參數,也沒有回傳值,基本上不太實用,只是展示如何建立閉包。

帶有參數或回傳值的閉包

以下建立一個帶有兩個參數的閉包:

def add = { a, b -> a + b }

assert add(3, 5) == 8

在這個例子中,閉包 add 會將兩個參數相加,然後將相加後的值回傳。注意在寫閉包時,不需要明確地寫出 return 敘述。

以閉包撰寫遞迴 (Recursion) 函式

閉包本質上也是函式,所以可以使用閉包撰寫遞迴函式。以下這個例子使用遞迴呼叫:

def fib
fib = { int n ->
    if (n <= 1) {
        return n
    }

    fib(n - 1) + fib(n - 2)
}

println fib(10)

寫遞迴程式的重點在於終止條件和縮小步驟,由於遞迴在程式設計中相當重要,最好要多練習一些題目。

注意以閉包撰寫遞迴函式時,要將識別字宣告及閉包實作的部分分開,因為 Groovy 需要使用該識別字撰寫遞迴函式。以本例來說,就是 fib

用 Memoization 加速遞迴函式的運算速度

傳統的遞迴在每次呼叫時都重新計算,這樣比較浪費運算效能,使用 memoization 的手法可以儲存先前計算的結果,加速遞迴運算。Groovy 內建 memoization 的支援,參考下例:

def fib
fib = { int n ->
    if (n <= 1) {
        return n
    }

    fib(n - 1) + fib(n - 2)
}

fib = fib.memoize()

println fib(10)

利用閉包自動管理系統資源

在撰寫 Java 程式時,需要手動將檔案等系統資源 (system resources) 釋放,而 Groovy 的閉包可自動處理這個問題,如以下例子:

new File('file.txt').eachLine { println it }
關於作者

身為資訊領域碩士,位元詩人 (ByteBard) 認為開發應用程式的目的是為社會帶來價值。如果在這個過程中該軟體能成為永續經營的項目,那就是開發者和使用者雙贏的局面。

位元詩人喜歡用開源技術來解決各式各樣的問題,但必要時對專有技術也不排斥。閒暇之餘,位元詩人將所學寫成文章,放在這個網站上和大家分享。