多重傳回值(Multiple Return Values)

Octave 的函數與一般程式語言函數有一個很大的差異,Octave 的函數可以有一個以上的傳回值,其使用方式為:

function [ret-list] = name (arg-list)
  body
endfunction

其中 namebodyarg-list 與前面提到的函數用法相同,而 ret-list 是一個逗點分隔序列,其包含多個從此函數傳回的變數名稱,此逗點分隔序列中至少要包含一個元素,若其只包含一個元素,其效果就與前面介紹的單一傳回值的函數相同。

下面這個函數會傳會一個向量中的最大值與其出現的位置:

function [max, idx] = vmax (v)
  idx = 1;
  max = v (idx);
  for i = 2:length (v)
    if (v (i) > max)
      max = v (i);
      idx = i;
    endif
  endfor
endfunction

這個例子中也可以將兩個傳回值合併成一個向量傳回,但這個方式並不適用每一種情況,例如在每個傳回值有不同的維度時,就很難合併成一個向量,另外使用多重傳回值的方式,可以為每個傳回值命名,使用起來也較為方便。

在 Octave 的函數中,有一個內建的 nargout 變數,其會儲存呼叫此函數時,所要求的傳回值個數,這個變數會自動初始化,就像 nargin 一樣,這個功能可以讓函數依照不同的輸出參數而有不同的功能,例如內建的 svd()lu() 函數就是這樣的函數。

若不指定傳回值而儲存在預設的 ans 變數時,nargout 不會將這個 ans 變數計算在內,此時的 nargout 的值為 0

函數的多個傳回值中可以只設定其中一部分的值,但這樣會出現一些警告訊息,例如:

function [x, y, z] = f ()
  x = 1;
  z = 2;
endfunction

執行 f()

[a, b, c] = f ()

輸出為

warning: f: some elements in list of return values are undefined
a =  1
b = [](0x0)
c =  2

沒有被設定的輸出參數,預設為空矩陣。

nargout ()
nargout (fcn_name)

在一個函數中呼叫 nargout() 函數可以傳回呼叫此函數時所要求的傳回值個數;nargout(fcn_name) 函數會傳回函數 fcn_name 最大的傳回值個數,若傳回 -1 則表示此函數可以傳回不固定個數的傳回值。例如:

f()

若這樣呼叫 f() 函數,則在 f() 函數中,nargout() 的值為 0,而

[s, t] = f ()

若是這樣呼叫 f() 函數,則在 f() 函數中 nargout() 的值為 2

nargout() 函數只適用於函數中,若是在最上層的命列呼叫,則會產生錯誤。

msgstr = nargchk (minargs, maxargs, nargs)
msgstr = nargchk (minargs, maxargs, nargs, "string")
msgstruct = nargchk (minargs, maxargs, nargs, "struct")

nargchk() 函數可用來檢查函數在呼叫時,是否有傳入正確個數的參數,若傳入的參數個數不正確,會傳回適當的錯誤訊息。此函數可用於檢查輸入的參數個數是否有在正確的範圍內。

msgstr = nargoutchk (minargs, maxargs, nargs)
msgstr = nargoutchk (minargs, maxargs, nargs, "string")
msgstruct = nargoutchk (minargs, maxargs, nargs, "struct")

nargoutchk() 函數可用來檢查函數在呼叫時,是否有指定正確個數的傳回值,若指定的傳回值個數不正確,會傳回適當的錯誤訊息。此函數可用於檢查指定的傳回值個數是否有在正確的範圍內。

可變長度參數列(Variable-length Argument Lists)

有的時候函數的參數個數在定義函數時還沒有辦法決定,例如一個傳回最小值的函數:

a = smallest (1, 2, 3);
b = smallest (1, 2, 3, 4);

所得到的 ab 都是 1,若要定義這樣的 smallest() 函數有一個辦法是將函數定義為

function val = smallest (arg1, arg2, arg3, arg4, arg5)
  body
endfunction

然後在 body 中以 nargin 變數判斷實際傳入的參數個數進而找出最小值,但這種方式只能用於有限個數的輸入參數。

Octave 針對這種不固定參數個數的函數,提供了一個特別的方式,就是將一個特別的參數 varargin 放在最後一個參數的位置,加入這個特殊參數表示這個函數可以接受不過定的參數個數,例如上面的 smallest() 函數可以這樣定義:

function val = smallest (varargin)
  body
endfunction

在函數的 body 中,輸入的參數可以經由 varargin 變數來取得,此變數是一個包含輸入參數的巢狀陣列(cell array,請參考巢狀陣列),所以這個函數最後可以定義成這樣:

function val = smallest (varargin)
  val = min ([varargin{:}]);
endfunction

這樣定義的 smallest() 函數可以處理任何個數的參數,而且其程式碼非常簡單。

下面這個例子比較複雜一點,它會輸出所有的參數:

function print_arguments (varargin)
  for i = 1:length (varargin)
    printf ("Input argument %d: ", i);
    disp (varargin{i});
  endfor
endfunction

執行此函數

print_arguments (1, "two", 3);

輸出為

Input argument 1:  1
Input argument 2: two
Input argument 3:  3
[reg, prop] = parseparams (params)

parseparams() 函數會將逗點分隔序列 params 分為兩部分,第一個部份是 reg,其包含從第一個元素到第一個字串出現之前,而第二個 prop 則會包含除了 reg 之外的部分,例如:

[reg, prop] = parseparams ({1, 2, "linewidth", 10})

輸出為

reg =

{
  [1,1] =  1
  [1,2] =  2
}

prop =

{
  [1,1] = linewidth
  [1,2] =  10
}