天天看點

《互動式程式設計 第2版》一2.5 函數

本節書摘來華章計算機《互動式程式設計 第2版》一書中的第2章 ,第2.5節,joshua noble 著 毛順兵 張婷婷 陳宇 沈鑫 任燦江 譯更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。

函數是什麼?

我們會把代碼分組,每個組裡有一行或多行代碼,而函數則是這些代碼組的名字。函數與變量很相似,函數也有類型和名字,隻不過它不隻是存放資訊,還會處理資訊。這跟基礎代數的概念很接近,變量可以用一個字母x表示,而函數則是一個指令,向指令輸入一些内容,期待它返還一個結果。如果用簡單的文字描述一個函數,大概會像這樣:“收到一筆錢,把收到的金額加在原來的金額上,最後把總金額告訴我。”

這件事可以分解成三部分:

收到一筆錢

累加金額

報告總金額

以上三部分可以這樣來考慮:函數收到什麼,做了什麼,傳回什麼。函數是程式中的指定行為,接收和處理特定類型的資料,完成後傳回結果。

我們就把上文提到的收錢的例子用代碼實作一下。定義一個變量放你所有的錢:

建立一個用來收錢的函數,把錢放到mybank裡,傳回錢的總數:

現在你已經建立了一個名叫moneyreceived()的函數。僞代碼和文字描述都有助于我們了解函數。“取得一個整數,加到銀行裡的現有金額中,報告總金額。”從圖2-6可以看到函數做了些什麼。

《互動式程式設計 第2版》一2.5 函數

圖2-6:函數的聲明

注意,return語句所傳回的内容要和标在函數名前面的資料類型一緻,這裡函數傳回的mybank就是一個整型變量。

函數定義好之後,就可以開始調用了。要調用函數,需要向它傳遞類型比對的參數。在函數moneyreceived()的例子裡,函數指定輸入一個整型參數。下面的語句都是正确的:

但是這樣就不對了:

錯誤在于傳遞給函數的參數類型不對,是以要看清楚函數的聲明,包括傳回值的類型、名字和參數。

return語句指出這個方法函數傳回的值的類型,就跟資料類型指定了變量可以存放什麼資料的道理一樣。不傳回任何值的函數會被聲明為void類型,其他情況下函數傳回值的類型需要明确聲明。例如,建立一個傳回一個字元的函數,可以這樣寫:

函數肯定是這樣一種格式:類型、函數名、括号以及被傳入的參數,如下所示。

這個函數接收了一個整型值,把這個值和2相乘,傳回相乘的結果。我們可以用帶有傳回值的函數去設定變量的值:

而下面這個例子則是調用了一個傳回字元的函數,傳回的結果取決于輸入的參數:

新變量的值可由函數的傳回值設定:

看上去有點不合規矩,但其實在使用中,一個函數是可以等價于它傳回的那個值的。上面這個例子中,最後一行的函數addexclamationpoints()就等價于它所傳回的那個字元串。隻要保證在指派之前,函數内部的所有處理都完成了,你就可以放心地直接調用函數設定變量的值。

由此可見函數類型是多麼重要。任何屬于整型的東西都可以為整型變量指派。

其中square()定義如下:

square()傳回一個整型值,你可以用它來設定一個整型變量。如果它傳回的是浮點型或是其他類型的結果,那就不可以用來設定整型變量了。再強調一次,函數傳回值的類型很重要。

給函數起個好名字,名字最好能指明函數的功能。上面例子裡的square就是個好名字,指明了這個函數是用來做平方運算的。一般情況下,把函數命名為動詞大有好處,因為這能從一開始就讓你去考慮這個函數的功能,而此後回過頭再次看這個函數的時候,函數名也能提醒你這個函數是做什麼用的。

函數規模要适中。如果一個函數包含了兩三百行的代碼,那麼我勸你還是把它分解為幾個小函數。這樣便于你把不同部分的代碼用在别的地方,也便于定位問題。把一個大函數分解為幾個小函數之後,原來兩三百行代碼的問題就可以精确定位為某幾行代碼的問題,進而能節省不少時間。

當你又要解決以前遇到過并解決好的問題時,就把以前使用過的代碼包裝成一個函數吧。例如你要經常調整圖檔尺寸,并把調好的圖檔存放到線上某個目錄下,你就可以寫一個函數來完成這些重複的操作:

resizeandsave(int picheight, int picwidth, string urltosave)

這樣看起來簡潔、省事又友善調試。代碼越短小,越容易查找内容和定位問題。

函數聲明之是以重要是因為兩個原因。第一,函數聲明告訴你向函數傳遞什麼參數,函數對資料作一些什麼處理,以及傳回什麼結果。第二,在編譯器看來,函數聲明以及它所接收的參數是獨一無二的。就算兩個函數擁有相同的名字,但如果其中一個接收的參數是2個字元串,而另一個接收3個字元串,則它們仍然是兩個不同的函數。一系列名字相同但參數不同的函數,可以讓你把同一個功能用在不同的場景。這種做法叫“重載”,同名函數擁有不同的參數。

我們拿動詞“draw”(畫)來打個比方。顯然“drawing a picture”(畫一幅畫)和“drawing a card”(畫一張卡片)是不一樣的。編譯器也是這樣看函數的。我們大可放心地定義同名的函數,編譯器能夠根據傳遞參數的不同分辨出它們。例如我們可以讓檢測視訊大小的函數接收整型或浮點型參數,編譯器會把它看成兩個獨立的函數,一個接收整型參數,另一個接收浮點型參數,就算它們都是同一個名字。調用這個函數的時候,如果傳入的參數是浮點型的,那麼就是調用浮點型參數對應的那一個函數。

這裡是processing裡重載函數的一個例子:

這個函數接收整型、字元串、字元以及整型數組。哪個版本的函數被調用,取決于傳入的參數的類型。

processing裡的可以這樣做:

警告:重載函數是非常強大的工具,一種方法隻需要經過輕微的改動(通過接收不同類型的參數)就能用在不同的場合。不過要注意,指定不同類型的參數,函數重載有效,例如:

繼續閱讀