原文連結:mp.weixin.qq.com/s/0TawtUd-sh27Ves...
學到什麼
如何呼叫函式?
如何建構函式?
函式如何返回多個值?
如何構造匿名函式?
如何傳遞函式?
內建函式有哪些?
介紹
函式是基本的程式碼塊,它負責將一個複雜問題分解為不同的函式提供呼叫與複用。
編寫函式時,無需關注順序,因為 Go 語言是編譯型的。
在 Go 語言中有三種函式型別:
基本格式:有命名的函式,直接呼叫完事。
匿名函式:沒有名字的函式。
結構體攜帶的函式:也可以稱之為方法,後續結構體再展開講解。
基本格式
func Fun1(arg1 T, arg2 T) T {
...
return r1
}
Fun1
為自定義的函式名稱。arg1
和arg2
為自定義引數名稱,宣告瞭兩個引數,可以再增加。T
代表 Go 語言中的任意型別,使用時替換成 int、string、slice 等等型別。小括號後緊跟函式返回值型別。
return
為函式返回的關鍵字,攜帶要返回的值,函式內之後的邏輯將不會執行。函式體的第一個花括號必須緊跟在函式後。
舉例:
// 計算兩個數之和並且返回
func AddNum(n1 int, n2 int) int {
return n1 + n2
}
函式也可以沒有返回值,這個時候就無需 return
關鍵字,例如: main()
入口函式、 init()
初始化函式。
當函式體內出現了 panic
函式,用於丟擲異常,這時如果定義了返回型別, return
關鍵字就可以選擇省略。
返回多個值
Go 語言函式中有個特點,可以多個值返回。在宣告返回值型別時,可以不指定名稱,也可以指定名稱,啥意思呢,往下看。
1. 無名稱
func Fun1(arg1 T, arg2 T) (T, T) {
...
return r1, r2
}
和“基本格式”的不同點:
當需要返回至少兩個值時,返回型別需要用小括號包裹,以逗號分隔。
使用
return
攜帶多個返回值。
2. 有名稱
func Fun1(arg1 T, arg2 T) (n1 T, n2 T) {
...
return
}
返回值型別指定了名稱後,在
return
返回時,可以不帶值,當然也可以都帶上。當有了名稱,即使是 1 個返回型別,也需要用小括號包裹。
為什麼有了名稱 return
就不用攜帶值呢?
因為相當於在返回時,初始化好了返回值,例如上面的格式中 n1
和 n2
就是初始化的兩個變數,在函式運算中,只要將返回結果存入 n1
和 n2
中,不存就按照初始化返回,當然也可以 return
攜帶值。
函式呼叫
構造好一個函式後,如何呼叫,格式如下:
r1, r2 := Fun1(param1, param2)
呼叫時傳遞了兩個引數,返回時接受兩個返回值。
如果接受多個值時,某個值我不想使用時,是不能擱置在那的,不然編譯器會報錯,需要使用下劃線 “_” 替代,表示我不用。
r1, _ := Fun1(param1, param2)
匿名函式
匿名函式就是在建構函式時,函式沒有名稱,想呼叫時,需要把匿名函式賦值給一個變數,或者在構造時直接呼叫。
1. 賦值給變數
fun1 := func (arg1 T, arg2 T) T {
...
return r1
}
賦值後, fun1
就是一個函式型別的變數, 呼叫格式:fun1(param1, param2)
。
2. 構造時呼叫
func (arg1 T, arg2 T) T {
...
return r1
}(param1, param2)
在建構函式時,花括號後緊跟引數傳遞(param1, param2)
,不需要賦值給一個變數,直接構造後馬上呼叫。
傳遞函式
在 Go 語言中,函式是“一等公民”,它和 int 、string 等等,都是一個級別,可以作為引數進行傳遞。
舉例:
// function/deliver.go
package main
// callback 是一個函式型別引數
func Calc(callback func(n1 int, n2 int) int) int {
x, y := 3, 4
return callback(x, y)
}
// 計算兩數之積
func Mul(n1 int, n2 int) int {
return n1 * n2
}
func main() {
// 第一個:傳遞一個匿名函式
Calc(func(n1 int, n2 int) int {
return n1 + n2
})
// 第二個:傳遞一個定義好的函式
Calc(Mul)
}
分別演示了兩種函式的傳遞方式,第一個匿名函式計算兩數之和,第二個用定義好的函式計算兩數之積。當然傳遞函式不止是通過引數,也可以是函式返回值、切片元素儲存、map值儲存等等。
宣告函式型別
宣告函式型別,意思就是可以自定義一個函式型別,給這個函式取一個別名,像例如 int
一樣很方便的去宣告變數或者引數型別。
type CallbackFunc func(n1 int, n2 int) int
現在自定義了一個名為 CallbackFunc
的函式型別,下來看如何使用:
func Calc(callback CallbackFunc) int {
...
}
Calc
函式有一個函式引數,這個引數的型別名稱為 CallbackFunc
。
函式引數
1. 引數型別省略
在宣告函式引數時,有時候會遇到連續宣告多個相同型別,這個時候,就可以只保留一個型別名稱。
// 沒精簡的
func Fun1(arg1 string, arg2 int, arg3 int)
// 精簡後
func Fun1(arg1 string, arg2, arg3 int)
精簡後, arg2
引數後省略了 int,這樣就和它後面的引數型別一致。
2. 值傳遞與引用傳遞
我們先定下引數稱呼,函式呼叫時傳遞的引數稱為實參,建構函式時的引數稱為形參。
在 Go 語言中,切片(slice)、map、介面(interface)、通道(channel)這樣的引用型別都是預設使用引用傳遞,在函式內修改形參是會改變實參的值。
對於切片,有種情況會打破引用傳遞這個規律,具體可以看看 《內建結合 - 切片》這篇文章。
對於其它剩下的型別,預設都是值傳遞,函式接收到的形參只是副本,函式內對形參的更改是不會影響到實參的。
如果希望更改實參的值,可以傳遞指標,在實參前增加“&”符號,表示取實參的地址,例如: Fun1(¶m)
。
3. 變長引數
當建構函式時,函式的最後一個引數是 ...T
形式時,稱為變長引數,它可以接受至少 0 個資料。
// 一個固定引數,一個變長引數
// nums 實際是一個切片
func Func1(str string, nums ...int) {
...
}
呼叫例子如下:
// 沒傳遞變長引數
Func1("miao")
// 給變長引數傳遞不同數量的值
Func1("miao", 1)
Func1("miao", 1, 2)
當把一個切片型別傳遞給可變引數時,在切片後跟著 ...
三個點,傳遞給變長引數,表示將切片元素展開。
nums := []int{1, 2, 3}
Func1("miao", nums...)
內建函式
在 Go 語言中,有一些函式無需匯入任何包就可以使用,下來對這些函式簡要說明一下。
總共 15 個內建函式,如下:
make:為切片,map、通道型別分配記憶體並初始化物件。
len:計算陣列、切片、map、通道的長度。
cap:計算陣列、切片、通道的容量。
delete:刪除 map 中對應的鍵值對。
append:將資料新增到切片的末尾。
copy:將原切片的資料複製到新切片中。
new:除切片、map、通道型別以外的型別分配記憶體並初始化物件,返回的型別為指標。
complex:生成一個複數。
real:獲取複數的實部。
imag:獲取複數的虛部
print:將資訊列印到標準輸出,沒有換行。
println:將資訊列印到標準輸出並換行。
close:關閉通道。
panic:觸發程式異常。
recover:捕捉 panic 的異常資訊。
總結
本篇我對 Go 語言中的函式進行了系統的講解,也列舉了 15 個內建函式。對於內建函式的使用,有的在前面文章使用過,有的還沒有,先做一個整體的瞭解,等到了用的時候再詳查。
本作品採用《CC 協議》,轉載必須註明作者和本文連結