前言
在 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 }