2008年5月6日 星期二

[Class Diagram] 參數方向 out 與 return 的不同

參數方向是指參數傳遞的方向,當我們要宣告一個函式(Function or Method)時,必須一並定義出參數的名稱與型態與方向,讓程式設計師在呼叫函式時有個依循的方向,所以UML在參數傳遞上定義了4種方向:

1. in-輸入參數
2. inout-輸入參數後,再將結果輸出。
3. return-回傳參數
4. out-輸出參數

這四種方向明確指出參數的行為特徵,分敘如下:

第一種in輸入參數,其實就是指Call by Value,這個一定會用到,應該不用解釋了。

第二種inout其實就是指Call by Reference或Call by Address,這個也很常用。

第三種retrun就是函式回傳值,也是絕對少不了的。

第四種out就比較少用到了,而且它跟return一樣都是用在輸出數值,可能會讓人搞不清楚有什麼不同。

在我使用的Delphi(pascal語言),參數就有宣告為out的用法,C/C++、Java或其他語言有沒有這種用法我就不清楚了。其實out與return在使用目的上是一樣的,都是在回傳數值,只是在於用法的不同而已。James Rumbaugh在「The Unified Modeling Language Reference Manual」書中有這麼段說明:

outAn output parameter. There is no input value. The final value is availabel to the caller.
return
A return value of a call. The value is available to the caller. Semantically, no different from an out parameter, but the result is available for use in a in-line expression.

他指出了兩者的不同在於:out是一種輸出參數(output parameter),是以參數的型式回傳數值;return是一種回傳數值(return value),以數值的方式回傳。

return是一種數值回傳的方法,所以在函式結束時,必須回傳數值給呼叫者,這種回傳方式只要宣告型態,不需要宣告名稱,而且回傳值只能宣告一個,在C/C++和Java指的就是保留字return的用法,例如(C/C++):

int methodA(int i, int j)
{
//do something
return 2;
}

紅色int是宣告這個methodA在結束時,必須回傳一個int型態的數值,而藍色return 2則是回傳一個int型態的值=2,這是典型的回傳數值的用法。

而out它是一種參數型態的回傳方法,使用上他是宣告在參數區,有參數名稱與資料型態,而且可以有很多個,需要幾個就宣告幾個,例如(delphi/pascal):

function methodA(i: integer; j: integer; out r: integer): integer;

藍色integer宣告這個methodA在結束時,必須回傳一個integer型態的數值給呼叫者,與前面的return例子是一樣的。這裡要解釋的是在參數區多宣告了一個r參數,並宣告方向為out,表示這個r參數目的僅用在輸出數值,不需要對它傳入數值而已。

out在用法上與Call by Reference是一樣的,或許有人會說,那就使用inout就好了,何需要多此一舉呢。其實還是有不同的,inout雖也能輸出數值,不過在呼叫函式時,宣告為inout的參數要先賦予初始值(不論宣告的是基本型態、物件參考或指標等任何有意義的值),表示函式需要先使用此變數。而out則不用賦予初始值,前面James Rumbaugh已經提到了,只要宣告一個變數去承接回傳值即可,這是inout、out兩者不同的地方。參數方向講到這裡out與return反而容易分辨,容易混淆的是在inout與out呢。

inout與out這樣區分應該是要讓語言使用上更明確與嚴謹,若呼叫函式時,必須賦予初始值給函式使用,而函式處理完畢會改變變數內容,那就使用inout。若呼叫的函式僅要回傳數值那就使用out。我在實務上out也完全沒用過,都是直接使用Call by Reference,其實這沒有對錯,可以完成任務就好。換個更嚴謹的說法,設計文件上只要明確指出參數的方向,Programer就算都只用Call by Reference,也能清楚的知道函式需不需要使用到該參數,進而決定要不要輸入數值。

我想到有個地方可以用的到,當我們要定義一堆API時,通常API的訊息代碼(message code)會用return回傳,若API還需要回傳更多參數或物件時,就可以使用out來回傳。

註:
文章有引述到uml-blog著作及相關書籍的部分內容,若有侵權請告知。

3 則留言:

  1. 我有一個疑惑,以下述為例:
    function methodA(i: integer; j: integer; out r: integer): integer;

    我可以使用result來存回傳值,如下:
    result=methodA(i,j);

    但是r呢?我該怎麼取得r值。

    回覆刪除
  2. 以呼叫文章中的methodA為例,在呼叫者methodB中直接宣告一個r變數來承接輸出值,但是可以不需給它初始值,因為methodA的r參數只用來接回傳值,不需要輸入數值,delphi語法範例:

    procedure methodB();
    var result,i,j,r: integer; //宣告變數
    begin

    i:= 1; //輸入要給初始值
    j:= 2; //輸入要給初始值

    result:= methodA(i,j,r); //r僅用來接回傳值,不需要給初始值

    if r=1 then showmessage('r=1');

    end

    回覆刪除