Go基礎知識複習之函數,defer,函數類型

上一篇我們已經知道go語言的map
今天介紹函數,defer,函數類型


函數

在我們前面關於go的所有文章中 很經常看到 func main()的內容
這個就是主函數 這個函數有個特點 就是不會有返回值 不會有參數
可以看到 函數的關鍵字就是func

在定義函數過程中 如果有定義返回類型的 就必須要return
換言之,有retrun就必須聲明返回值的類型(多個返回值 就需要用括號包裹起來)
並且 go語言中 函數的參數 是沒有默認值

語法:

//返回值可以命名 也可以不命名  同樣 參數也可以
func 函數名(參數 參數類型)(返回值 返回值類型){}

//匿名函數
func(形參){}(實參)

示例:
注意 函數的調用 必須在main函數中才可以調用

package main

import "fmt"

//定義一個 求合函數
func add(a int,b int)(c int){
	return a + b
}

func main(){
	//調用求合函數
	res := add(1,2)
	fmt.Println(res)
	//匿名函數
	func(x,y int){
		fmt.Println(x,y)
	}(1,2)
}

函數的定義有着多種寫法 這邊簡單概括一下:

沒有參數的 沒有返回值的
func f1(){
	fmt.Println("這是f1函數 調用我 我就輸出")
}
//在main函數中調用的寫法
f1()
沒有參數 有返回值的
func f2()string{
	return "f2"
}
//在main函數中調用的寫法
f2 := f2()
fmt.Println(f2)
有命名參數 有命名返回值
func f3(x int , y int)(ret int){
	return x + y
	//這裏不需要在通過ret進行接收
}
//在main函數中調用的寫法
f3:= f3(2,3)
fmt.Println(f3)
多個返回值

func f4()(int,string){
	return 1,"zzs"
}
//在main函數中調用的寫法 需要多個值接收
f41,f42:= f4()
fmt.Println(f41,f42)
參數類型相同的情況下簡寫
func f5(x,y int){
	return x-y
}
//在main函數中調用的寫法
f5:= f5(8,6)
fmt.Println(f5)
可變長參數

也就是可以傳多個但是其實就是一個切片
這個參數 只能做爲最後一個參數

func f6(x string,y ...int){
	fmt.Println(x)
	fmt.Println(y)
}
//在main函數中調用的寫法
f6("zzs",1,2,3,4,4,56,7)

新建一個文件夾func 文件夾下新建main.go
調用上述的各種函數 查看效果吧

package main
import "fmt"
func f1(){
	fmt.Println("這是f1函數 調用我 我就輸出")
}
func f2()string{
	return "f2"
}
func f3(x int , y int)(ret int){
	return x + y
	//這裏不需要在通過ret進行接收
}
func f4()(int,string){
	return 1,"zzs"
}
func f5(x,y int)int{
	return x-y
}
func f6(x string,y ...int){
	fmt.Println(x)
	fmt.Println(y)
}
func main(){
	f1()

	f2 := f2()
	fmt.Println(f2)

	f3:= f3(2,3)
	fmt.Println(f3)

	f41,f42:= f4()
	fmt.Println(f41,f42)

	f5:= f5(8,6)
	fmt.Println(f5)

	f6("zzs",1,2,3,4,4,56,7)
}

defer

defer就是 把後面的語句延遲執行 延遲到函數即將返回的時候執行
所以 defer只能用於函數中

多用於處理資源的釋放 文件句柄 數據庫連接 socket連接

如果有多個defer 那麼越上面的defer的語句越晚執行

關於上述的函數即將返回的時候這個描述
如何理解?

要知道 在go語言中 return不是原子操作 屬於非原子操作
所謂的原子操作就是 一步到位 非原子操作是多步
所以go的return分爲兩位:

  1. 返回值賦值
  2. 值進行返回

因此,如果存在defer,那就是在上述的兩步之間執行!


示例:

func main(){
	fmt.Println(1)
	defer fmt.Println(2)
	defer fmt.Println(3)
	fmt.Println(4)
}
//代碼通常都是 從上執行到下 加上defer之後 可以看到結果:1 4 3 2 這就是defer的使用

單看上述的例子 可能還無法理解

加深defer的印象

新建文件夾defer 文件夾下新建文件 main.go

package main

import  "fmt"

//場景1
func demo1()int{
	x := 5
	//匿名函數
	defer func(x int){
		x++
	}(x)
	return x
}
//場景2
func demo2()(x int){
	defer func(){
		x++
	}()
	return 5
}
//場景3
func demo3()(y int){
	x:=5
	defer func(){
		x++
	}()
	return x
}
//場景4
func demo4()(x int){
	defer func(x int){
		x++
	}(x)
	return 5
}
func main(){
	fmt.Println(demo1()) //5	此時修改的是 x 而返回值5已經賦值給x了 所以結果是   5 
	fmt.Println(demo2()) //6	返回之前進行賦值
	fmt.Println(demo3()) //5	x賦值給5  x是5 所以是 y 5
	fmt.Println(demo4()) //5	運算後賦值 所以是
}

函數類型

爲什麼要了解函數的類型呢 因爲函數也可以當作參數 所以需要寫對正確的函數結構體才能實現程序的運行
函數類型可以通過 fmt包的Printf("%T \n",要輸出的對象)
下面我將通過例子 將各種形式的函數 打印出他們的類型:

新建文件夾func_type 文件夾下新建main。

package main

import "fmt"

func f1(){
	fmt.Println("f1")
}
func f2()int{
	return 2
}
func f3(f func() int){
	ret := f()
	fmt.Println(ret)
}
func f4(x,y int)int{
	return x+y
}
func f5(x func() int)func(int,int)int{
	return func(a,b int)int{
		return a+b
	}
}
func main(){
	fmt.Printf("%T \n",f1)//func()
	fmt.Printf("%T \n",f2)//func() int

	//調用f3
	f3(f2)
	fmt.Printf("%T \n",f3)//func(func() int)
	fmt.Printf("%T \n",f4)//func(int,int) int
	fmt.Printf("%T \n",f5)//func(func() int)func(int,int)int
}

關於函數的介紹就先到這裏 很重要的一個知識點!
有問題歡迎在評論區留言
未完待續。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章