返回值

返回值

一個函式的函式名即是該函式的代表,也是一個變數。由於函式名變數通常用來把函式的處理結果數據帶回給調用函式,即遞歸調用,所以一般把函式名變數稱為返回值。

C++中

函式可以有返回值,也可以沒有返回值。對於沒有返回值的函式,功能只是完成一個操作,應將返回值類型定義為void,函式體內可以沒有return語句,當需要在程式指定位置退出時,可以在該處放置一個

例:

函式可以有返回值,只要 return 就可以給出一個。不過我們常常不用它--有兩個原因:

1、C/C++里返回值是複製出去的,而對於大的對象,複製的代價很高;

2、有些對象是不能複製的--至少編譯器不知道怎么複製--比如數組。

於是我們有了很多這樣的函式:

bool GetObj(ObjType& obj);

bool Encode(const char* src, char* dest);

用一個參數來代替返回值,而返回值只是指示函式執行是否成功。我本人一直固執的認為,這是C的處理方式,C++不該這樣,返回就是返回,就該光明正大的返回,而不是在文檔里為某個參數悄悄的註上: // out

誠然返回一個大對象是困難的,但這個困難是 C 程式設計師的,而不是 C++ 程式設計師的 -- 我們可以返回指針。C也有指針,但很少有人敢在 C 函數裡返回一個指針,因為:

1、如果指針指向棧變數,毫無疑問,要么你不用這個返回值,要么是一個錯誤;

2、如果指針指向堆變數,要么你在祈禱用這個函式的程式設計師會好好的看文檔且足夠細心會調用 free,要么就是記憶體泄漏;

3、如果指針指向 static 變數,那么用這個函式的程式設計師牢牢記住“下次調用這個函式以後,上次的返回值也會跟著變”,要么就是你被別人罵成“專出 BUG 的垃圾”。

在C++里直接返回裸指針的話,情況並不會有什麼起色,不過 C++ 有智慧型指針的,通常它們指向堆變數,占用的空間和裸指針一樣大。考慮前面第一個函式,我們寫成:

std::auto_ptr<ObjType> GetObj();

那么一切迎刃而解,返回值如果你不要,作為臨時變數,會立即被析構,返回的對象被釋放;如果你要,就得賦值給另一個智慧型指針。總之不用程式設計師記得,編譯器會保證這個對象的釋放。

考慮第二個函式,稍微有一點麻煩,因為 auto_ptr 是不能用來持有數組的,不過,在C++的世界裡,std::string 幾乎總是比 char* 好用:

std::auto_ptr<std::string> Encode(const char* src);

最後考慮最麻煩的情況:

bool AssembleObjList(ObjType objList[], size_t length);

這種類型的函式無論是在 C標準庫里,還是在各種作業系統的 API 里,比比皆是,事實上它存在兩大缺陷:

1、如果需要的數量超出給出的,要么是一個安全問題(經典的緩衝區溢出,如 strcpy),要么是失敗,程式設計師不得不作出估計--眾所周知,程式設計師的估計能力比他們的薪水低得多;

2、如果執行成功,到底 Assemble 了多少個?

於是我們見到了這樣的函式:

bool AssembleObjList(ObjType objLIst[], size_t* lengthPtr);

這個函式通常是兩步調用的:

size_t length = 0;

AssembleObjList(0, ≤ngth);

ObjType* objList = new ObjType[length];

AssembleObjList(objList, ≤ngth);

for(size_t i=0; i<length; ++i)// 處理每個元素

這種形式能解決上面列出的兩個問題,但這實在是太麻煩、太可惡了。我的答案仍然是--C++程式設計師應該用C++的庫:

std::auto_ptr<std::vector<ObjType> > AssembleObjList();

又乾淨,又舒服!

C++標準庫里居然沒有一個可以持有數組的智慧型指針,所以 boost庫不錯,可以這樣:

std::pair<boost::scoped_array<ObjType>, size_t> AssembleObjList();

可惜這個並不比標準庫的解法更優秀--因為要返回數目的緣故,不過我個人更喜歡這個解,因為他更接近最優的解--傳說中的 trule 手法:

TruleVector<ObjType> AssembleObjList();

其中 TruleVector是這樣一個模板:它只有兩種操作,一是構造,二是自動轉型為 std::vector,而且它具有 “auto_ptr 式的所有權轉移語義”。也就是說,TruleVector除了作為數組型的返回值,你無法把他用於其它任何任務。

不過由於 std::vector具有值語義,所以寫的代碼還是稍微有一點不同尋常:

typedef std::vector<ObjType> ObjListType;

ObjListType list;

list.swap(AssembleObjList());

最後一句在有的產品上可能要寫成:

list.swap(static_cast<ObjListType>(AssembleObjList()));

這樣彆扭的原因,可以歸咎於C++庫里缺一個引用語義的線性容器。

php中

值通過使用可選的返回語句返回。任何類型都可以返回,其中包括列表和對象。這導致函式立即結束它的運行,並且將控制權傳遞迴它被調用的行。更多信息見 return()

例子 17-11. return()的用法

<?php

function square($num)

{

return $num * $num;

}

echo square(4); // outputs '16'.

?>函式不能返回多個值,但為了獲得簡單的結果,可以返回一個列表。

例子 17-12. 返回一個數組以得到多個返回值

<?php

function small_numbers()

{

return array (0, 1, 2);

}

list ($zero, $one, $two) = small_numbers();

?>從函式返回一個引用,必須在函式聲明和指派返回值給一個變數時都使用引用操作符 & :

例子 17-13. 由函式返回一個引用

<?php

function &returns_reference()

{

return $someref;

}

$newref =& returns_reference();

?>

相關詞條

相關搜尋

熱門詞條

聯絡我們