Go語言的函數聲明以func辨別,後面緊接着函數名、參數清單、傳回參數清單以及函數體。
1.普通函數的聲明形式
func 函數名(參數清單) (傳回參數清單){
//函數體
}
注意:
在同一個包内,函數名不能相同
參數清單中如果多個參數類型相同,則可放在一起聲明。如func test(a, b int) {}同時聲明a, b為int類型
函數可以同時傳回多個值
2.同一類型傳回值
func typedTwoValues() (int, int) {
return 1, 2
}
a, b = typedTwoValues()
fmt.Println(a, b)
3.帶有變量名的傳回值
func namedRetVallues() (a, b int) {
a = 1
b = 2
return
}
當函數使用命名傳回值時,可以在return中不填寫傳回值清單,如果填寫也是可行的。
4.參數傳遞
Go語言中傳入和傳回參數在調用和傳回時都使用值傳遞,這裡要注意的是指針、切片和map等引用型對象指向的内容在參數傳遞中不會發生複制,而是将指針進行複制,類似于建立一次引用。
5.函數變量
在Go語言中,函數也是一種類型,可以和其他類型一樣被儲存在變量中。
func fire() {
fmt.Println("call fire")
}
func foo1(a int) int{
}
var f1 func() //定義函數變量f,無參無傳回值
f1 = fire
var f2 func(int) int = foo1
6.匿名函數
Go語言支援匿名函數,即在需要使用函數時,再定義函數,匿名函數沒有函數名,隻有函數體,函數可以被作為一種類型指派給函數類型的變量,匿名函數也往往以變量方式被傳遞。
匿名函數經常被用于實作回調函數、閉包等。
(1)匿名函數定義格式
func(函數清單) (傳回參數清單) {
//函數體
}
(2)定義時調用匿名函數
func(data int) {
fmt.Println("hello", data)
}(100)
(3)将匿名函數指派給變量
f := func(data int) {
fmt.Println(data)
}
f(100) //調用匿名函數
(4)匿名函數作為回調函數
func visit(list []int, f func(int)){
//to do
for _, v := range list {
f(v)
}
}
visit([]int{1, 2, 3}, func(data int) {
fmt.Println(data)
})
(5)匿名函數實作操作封裝
var skill = map[string]func() {
"fire":func() {
fmt.Println("chicken fire")
},
"run":func() {
fmt.Println("soldier run")
},
}
7.變參函數
所謂可變參數,是值參數數量不固定的函數形式。Go語言支援可變參數特性,函數聲明和調用時沒有固定數量的參數。
(1)變參函數定義格式
func 函數名(固定參數清單, v ... T) (傳回參數清單) {
//todo
}
可變參數一般被放置函數清單的末尾,前面是固定參數清單
v為可變參數變量,類型為[]T
T為可變參數的類型,如果T為interface{},傳入的可以是任意類型
(2)所有參數都是可變參數
以fmt.Println()為例:
func Println(a ...interface{}) (n int, err error) {
return Fprintln(os.Stdout, a...)
}
(3)部分參數是可變參數
以fmt.Printf()函數為例:
func Printf(format string, a ...interface{}) (n int, err error) {
return Fprintf(os.Stdout, format, a...)
}
(4)在多個可變參數函數中傳遞參數
func rawPrint(rawList ...interface{}) {
//todo
}
func Print(slist ...interface{}) {
rawPrint(slist...) //這種用法在切片的append()中也見過
}
func main() {
Print("hello", 123)
}
8.defer(延遲執行語句)
Go語言的defer語句會将其後面跟随的語句進行延遲處理。在defer歸屬的函數即将傳回時,将延遲處理的語句按defer的逆序進行執行。也就是說,先被defer的語句最後被執行,最後被defer的語句,最先被執行。
func main() {
defer fmt.Println("defer begin")
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
defer fmt.Pritnln("defer end")
}
輸出結果:
defer begin
defer end
3
2
1
通過defer聲明調用的函數的調用順序和C++析構的調用函數類似,都是一個棧的調用順序、