函式構成了**執行的邏輯結構,在go語言中,函式的基本組成為:關鍵字 func、函式名、引數列表、返回值、函式體和返回語句,每乙個程式都包含很多的函式,函式是基本的**塊。
因為go語言是編譯型語言,所以函式編寫的順序是無關緊要的,鑑於可讀性的需求,最好把 main() 函式寫在檔案的前面,其他函式按照一定邏輯順序進行編寫(例如函式被呼叫的順序)。
編寫多個函式的主要目的是將乙個需要很多行**的複雜問題分解為一系列簡單的任務來解決,而且,同乙個任務(函式)可以被多次呼叫,有助於**重用(事實上,好的程式是非常注意 dry 原則的,即不要重複你自己(don』t repeat yourself),意思是執行特定任務的**只能在程式裡面出現一次)。
當函式執行到**塊最後一行}之前或者 return 語句的時候會退出,其中 return 語句可以帶有零個或多個引數,這些引數將作為返回值供呼叫者使用,簡單的 return 語句也可以用來結束 for 的死迴圈,或者結束乙個協程(goroutine)。
go語言裡面擁三種型別的函式:
普通函式宣告(定義)
函式宣告包括函式名、形式引數列表、返回值列表(可省略)以及函式體。
func 函式名(形式引數列表)
(返回值列表)
形式引數列表描述了函式的引數名以及引數型別,這些引數作為區域性變數,其值由引數呼叫者提供,返回值列表描述了函式返回值的變數名以及型別,如果函式返回乙個無名變數或者沒有返回值,返回值列表的括號是可以省略的。
如果乙個函式宣告不包括返回值列表,那麼函式體執行完畢後,不會返回任何值,在下面的 hypot 函式中:
func
hypot
(x, y float64
)float64
fmt.
println
(hypot(3
,4))
// "5"
x 和 y 是形參名,3 和 4 是呼叫時的傳入的實數,函式返回了乙個 float64 型別的值,返回值也可以像形式引數一樣被命名,在這種情況下,每個返回值被宣告成乙個區域性變數,並根據該返回值的型別,將其初始化為 0。
如果乙個函式在宣告時,包含返回值列表,那麼該函式必須以 return 語句結尾,除非函式明顯無法執行到結尾處,例如函式在結尾時呼叫了 panic 異常或函式中存在無限迴圈。
正如 hypot 函式一樣,如果一組形參或返回值有相同的型別,我們不必為每個形參都寫出引數型別,下面 2 個宣告是等價的:
func
f(i, j, k int
, s, t string
)func
f(i int
, j int
, k int
, s string
, t string
)
下面,我們給出 4 種方法宣告擁有 2 個 int 型引數和 1 個 int 型返回值的函式,空白識別符號_可以強調某個引數未被使用。
func
add(x int
, y int
)int
func
sub(x, y int
)(z int
)func
first
(x int,_
int)
intfunc
zero
(int
,int
)int
fmt.
printf
("%t\n"
, add)
// "func(int, int) int"
fmt.
printf
("%t\n"
, sub)
// "func(int, int) int"
fmt.
printf
("%t\n"
, first)
// "func(int, int) int"
fmt.
printf
("%t\n"
, zero)
// "func(int, int) int"
函式的型別被稱為函式的識別符號,如果兩個函式形式引數列表和返回值列表中的變數型別一一對應,那麼這兩個函式被認為有相同的型別和識別符號,形參和返回值的變數名不影響函式識別符號也不影響它們是否可以以省略引數型別的形式表示。
每一次函式在呼叫時都必須按照宣告順序為所有引數提供實參(引數值),在函式呼叫時,go語言沒有預設引數值,也沒有任何方法可以通過引數名指定形參,因此形參和返回值的變數名對於函式呼叫者而言沒有意義。
在函式中,實參通過值傳遞的方式進行傳遞,因此函式的形參是實參的拷貝,對形參進行修改不會影響實參,但是,如果實參包括引用型別,如指標、slice(切片)、map、function、channel 等型別,實參可能會由於函式的間接引用被修改。
函式的返回值
go語言支援多返回值,多返回值能方便地獲得函式執行後的多個返回引數,go語言經常使用多返回值中的最後乙個返回引數返回函式執行中可能發生的錯誤,示例**如下:
conn, err :=
connecttonetwork
()
在這段**中,connecttonetwork 返回兩個引數,conn 表示連線物件,err 返回錯誤資訊。
其它程式語言中函式的返回值
c/c++ 語言中只支援乙個返回值,在需要返回多個數值時,則需要使用結構體返回結果,或者在引數中使用指標變數,然後在函式內部修改外部傳入的變數值,實現返回計算結果,c++ 語言中為了安全性,建議在引數返回資料時使用「引用」替代指標。
c# 語言也沒有多返回值特性,c# 語言後期加入的 ref 和 out 關鍵字能夠通過函式的呼叫引數獲得函式體中修改的資料。
lua 語言沒有指標,但支援多返回值,在大塊資料使用時方便很多。
go語言既支援安全指標,也支援多返回值,因此在使用函式進行邏輯編寫時更為方便。
1) 同一種型別返回值
如果返回值是同一種型別,則用括號將多個返回值型別括起來,用逗號分隔每個返回值的型別。
使用 return 語句返回時,值列表的順序需要與函式宣告的返回值型別一致,示例**如下:
func
typedtwovalues()
(int
,int
)func
main()
**輸出結果:
1
2
純型別的返回值對於**可讀性不是很友好,特別是在同型別的返回值出現時,無法區分每個返回引數的意義。
2) 帶有變數名的返回值
go語言支援對返回值進行命名,這樣返回值就和引數一樣擁有引數變數名和型別。
命名的返回值變數的預設值為型別的預設值,即數值為 0,字串為空字串,布林為 false、指標為 nil 等。
下面**中的函式擁有兩個整型返回值,函式宣告時將返回值命名為 a 和 b,因此可以在函式體中直接對函式返回值進行賦值,在命名的返回值方式的函式體中,在函式結束前需要顯式地使用 return 語句進行返回,**如下:
func
namedretvalues()
(a, b int
)
**說明如下:
第 1 行,對兩個整型返回值進行命名,分別為 a 和 b。
第 3 行和第 4 行,命名返回值的變數與這個函式的布局變數的效果一致,可以對返回值進行賦值和值獲取。
第 6 行,當函式使用命名返回值時,可以在 return 中不填寫返回值列表,如果填寫也是可行的,下面**的執行效果和上面**的效果一樣。
func
namedretvalues()
(a, b int
)
提示
同一種型別返回值和命名返回值兩種形式只能二選一,混用時將會發生編譯錯誤,例如下面的**:
func
namedretvalues()
(a, b int
,int
)
mixed named and unnamed function parameters
意思是:在函式引數中混合使用了命名和非命名引數。
呼叫函式
函式在定義後,可以通過呼叫的方式,讓當前**跳轉到被呼叫的函式中進行執行,呼叫前的函式區域性變數都會被儲存起來不會丟失,被呼叫的函式執行結束後,恢復到呼叫函式的下一行繼續執行**,之前的區域性變數也能繼續訪問。
函式內的區域性變數只能在函式體中使用,函式呼叫結束後,這些區域性變數都會被釋放並且失效。
go語言的函式呼叫格式如下:
返回值變數列表 = 函式名(引數列表)
下面是對各個部分的說明:
例如,加法函式呼叫樣式如下:
result :=
add(1,
1)
go語言 函式的宣告
1 宣告格式 函式宣告包括函式名 形式引數列表 返回值列表 可省略 以及函式體 func name 引數列表 返回值列表 示例1 func f i,j int s,t string 等於 func f i int j int s string t string 示例2 func add x,y in...
函式宣告 函式定義 函式原型
函式宣告 函式定義 函式原型 1.void threeline void 宣告了乙個函式的名字 引數型別和個數 返回值型別,這叫做函式原型 2.在 中可以單獨寫乙個函式原型,後面加 結束,沒有函式體,如void threeline void 這就只能叫函式宣告而不能叫函式定義,只有帶函式宣告的才叫定...
c語言 函式宣告定義總結
巢狀呼叫很好理解,就是在乙個子程式裡呼叫另乙個子程式。void print char a void hello 而鏈式訪問就是把乙個函式的返回值直接當作實參傳遞給下乙個函式。int ret strlen strcat hello world 上例中strcat 的返回值是char型別,是目標串的首位...