Lua 教學 -- 函式
 

前面介紹的迴圈,可以讓電腦進行重覆的工作。例如,假設我們想要利用電腦來計算 Fibonacci 數列,即

 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...

即每個數字是前兩個數字的和,我們可以利用下面的程式:

io.write("enter n: ")
n = io.read()
a = 1
b = 1
for i = 3,n do
    c = a + b
    a = b
    b = c
end
print(b)

在上面的程式中,a 和 b 分別存放「前兩個數字」。在 for 迴圈中,c 存放「前兩個數字」的和,然後再將 a 和 b 更新為新的「前兩個數字」,這樣一來就可以計算出 Fibonacci 數列。

但是,假設我們要寫一個程式,其中有很多地方都需要計算 Fibonacci 數列,那總不能每個要用到的地方,都把上面的程式重覆輸入一次吧!之前也提過,這樣會造成很多潛在的問題,最明顯的是萬一程式需要修改,則每個重覆的地方都要修改到,如果有一個地方漏掉沒改到,就可能產生錯誤。

為了避免需要重覆輸入程式,在程式語言中,有一個觀念,稱為「函式」(function)。把一段程式做成函式,就可以重覆在不同的地方使用,非常方便。事實上我們已經用過函式了。例如,上面的程式中,io.write、io.read、及 print 都是函式,只不過它們都是由系統提供的而已。現在,我們要來寫自己的函式。

在 Lua 中,要寫自己的函式相當的容易。例如,要把上面的程式修改成函式,只需要改成:

function fib (n)
    local a = 1
    local b = 1
    for i = 3,n do
        local c = a + b
        a = b
        b = c
    end
    return b
end

第一行的 function 表示我們要建立一個函式。在 function ... end 之間,就是函式的內容。fib 是函式的名稱。(n) 表示我們的函式有一個「參數」(parameter),參數是可以在使用函式時,指定的變數。

在函式中,基本上的內容和原來的程式是一樣的,不過,各個變數名稱前面多了一個 local。local 表示這個變數,只在這個函式中使用而已。而且,當函式結束的時候,這個變數就失去作用。這種變數稱為「區域變數」如果我們不使用 local,那麼,如果程式其它的地方有用到 a 和 b 變數,那它們的內容就會在呼叫 fib 函式後,被 fib 函式改變。通常這不是我們想要的結果。

在函式的最後,我們看到了 return b。return 會讓函式結束,而且把 b 的值「傳回去」。簡而言之,現在有了 fib 函式,要計算 Fibonacci 數列,只需要呼叫它就可以了:

io.write("enter n: ")
n = io.read()
fn = fib(n)
print(fn)

整個程式的檔案內容如下:

function fib (n)
    local a = 1
    local b = 1
    for i = 3,n do
        local c = a + b
        a = b
        b = c
    end
    return b
end

io.write("enter n: ")
n = io.read()
fn = fib(n)
print(fn)

函式不一定要有參數或傳回值。例如,下面的函式:

function hello ()
    print("hello, world!")
end

就沒有參數也沒有傳回值。呼叫這個函式的方式如下:

hello()

這樣它就會印出 hello, world! 的字串。

函式的參數和傳回值可以有很多個。例如,下面的函式有三個參數:

function multiply (x, y, z)
    return x*y*z
end

呼叫方式為:

r = multiply(3, 4, 5)
print(r)

會印出 60。

除了參數可以有很多個之外,傳回值也可以有很多個。例如,以下的函式:

function addsub (x, y)
    return x+y, x-y
end

呼叫方式為:

a,b = addsub(3, 6)
print(a, b)

會印出 9   -3。如果只想取得第一個傳回值,則可以寫:

a = addsub(3, 6)
printf(a)

則會印出 9,第二個傳回值會被丟棄。那有沒有辦法只取得第二個傳回值呢?答案是可以的,只要把第一個傳回值用底線 '_' 符號代替就可以了,如下:

_,a = addsub(3, 6)
print(a)

會印出 -3。事實上,在這裡 _ 仍是一個變數,所以並不是真的丟棄了第一個傳回值。例如:

_,a = addsub(3, 6)
print(_)

會印出 9。在 Lua 中,習慣上使用 _ 來做為一個「用不到」的變數。

要特別注意的是,雖然 _ 是一個合法的變數名稱,但是由 _ 開頭,後面接上大寫字母的變數,通常是用在系統保留的變數中。例如,_VERSION 是一個 Lua 的系統保留變數,表示目前 Lua 的版本。因此,在幫變數取名字的時候,要避免使用這樣的名稱,以免發生衝突。