複雜的 Octave 程式可以經由定義函數的方式讓其架構更精簡,函數可以直接在命令列中定義或是寫在外部的檔案中,而其使用起來就像內建的函數一樣。
定義函數(Defining Functions)
要定義一個函數最簡單的方式就是
function name body endfunction
這樣會定義一個名稱為 name
的函數。函數的命名規則與一般的變數相同,可以使用英文字母、數字或下底線,但開頭不可以是數字,函數的命名空間與變數是共用的。body
部份包含了一個或多個敘述,其指定了此函數所要執行的程式碼,這是定義函數時最重要的部份。例如:
function hello printf("Hello.\n"); endfunction
這樣會定義一個名稱為 hello
函數,呼叫此函數會使用 printf()
函數輸出字串 "Hello.\n"
(關於 printf()
函數可以參考輸入與輸出)。當定義完一個函數之後,可以直接使用函數的名稱來呼叫此函數,例如:
hello
輸出為
Hello.
若要將變數傳入函數中,可以使用參數,使用方法為:
function name (arg-list) body endfunction
其中 arg-list
是一個包含傳入參數的逗點分個序列,當函數被呼叫時,這些參數的名稱就會用來當作變數名稱,儲存函數呼叫時所傳入的值。arg-list
可以是空的,這個情況就跟上面沒有使用小括號的定義方式相同。
將上面的例子加入傳入參數:
function hello(msg) printf("Hello, %s.\n", msg); endfunction
呼叫此函數
hello("world")
輸出為
Hello, world.
若要將函數中的運算結果傳回,則可使用指定運算子加入函數的傳回值:
function ret-var = name (arg-list) body endfunction
ret-var
是一個變數名稱,其儲存的值會作為整個函數的傳回值,這個變數必須在函數結束之前定義,以便可以讓函數作為傳回值。
在函數中所使用的變數都是此函數的區域變數,包含 arg-list
與 ret-var
也都是區域變數,若要在函數中存取全域變數,可以參考全域變數。
下面的例子會計算一個向量中每個元素的平均值:
function retval = avg (v) retval = sum (v) / length (v); endfunction
執行此函數:
avg([1, 3, 5, 7])
輸出為
ans = 4
若將上面的 avg()
函數改寫成這樣
function retval = avg (v) if (isvector (v)) retval = sum (v) / length (v); endif endfunction
此時若是呼叫此函數而傳入矩陣
val = avg([1, 2; 4, 6])
則會出現警告訊息:
warning: avg: some elements in list of return values are undefined val = [](0x0)
這是因為當傳入矩陣時,if
判斷式中的程式碼將不會執行,因此導致 retval
沒有被定義,為了避免出現這種含糊不清的訊息,建議在定義函數時,將每一種可能發生的情況都考慮進去,並且確定傳回值都有被定義,在必要時也能輸出較詳細的錯誤訊息,例如這個 avg()
函數就可以改寫成這樣:
function retval = avg (v) retval = 0; if (isvector (v)) retval = sum (v) / length (v); else error ("avg: expecting vector argument"); endif endfunction
這樣可以解決傳入參數型態不符合的問題,但是若在呼叫此函數時沒有傳入任何參數,則還是會出現錯誤。若沒有更詳細的錯誤檢查,Octave 所輸出的錯誤訊息常常會讓程式設計者很難追蹤錯誤所發生的位置,為了處理這類的問題,Octave 提供了一個特殊的內建變數 nargin
,當函數被呼叫時,這個變數會自動被初始化,其會紀錄此函數在呼叫時所傳入的參數個數。上面的 avg()
函數可以更改成這樣:
function retval = avg (v) retval = 0; if (nargin != 1) usage ("avg (vector)"); endif if (isvector (v)) retval = sum (v) / length (v); else error ("avg: expecting vector argument"); endif endfunction
在 Octave 中若是在呼叫函數時傳入的參數個數超過函數所定義的個數,預設是不會產生錯誤的,但是會出現這樣的情況代表在程式中的某個地方一定有錯誤;若是傳入的變數比函數所宣告的個數少,在函數中使用那些沒有傳入的變數將會導致錯誤。為了避免以上兩種錯誤,建議在函數中加入對於這兩種情況的檢查,並針對各種錯誤輸出詳細的錯誤訊息。
nargin () nargin (fcn_name)
若在函數中呼叫 nargin()
函數,則會傳回呼叫此函數時所傳入的參數個數;若在最上層呼叫 nargin()
則會傳回執行 Octave 時所傳入的命令列參數個數。nargin(fcn_name)
函數可以查詢函數 fcn_name
可以接受的最大參數個數,若傳回 -1
則表示此函數可以接受各種不同的參數個數。
inputname (n)
在一個函數中呼叫 inputname(n)
函數會傳回呼叫此函數時所傳入的第 n
個參數。
val = silent_functions () old_val = silent_functions (new_val)
silent_functions()
函數可以查詢或設定是否要顯示函數中程式碼的執行輸出,若這個選項設定為 false
,則 Octave 會顯示函數中沒有使用分號結尾的指令執行結果,預設是設為 false
。例如:
function test_output x = 1 endfunction
執行 test_output()
函數
test_output
輸出為
x = 1
若是將 silent_functions()
設為 true
:
silent_functions(true) test_output
則執行 test_output
時就不會輸出。