go語言函數

  • go語言中函數重載是不允許的
  • 函數可以以聲明的方式被使用,作爲一個函數類型:
type binOp func(int, int) int
  • 函數可以作爲一個變量進行傳遞,當兩個函數變量進行比較時,當且僅當兩個函數相同,或者都爲nil時才相等

  • 目前go語言中沒有泛型的概念,但是可以通過接口,特別是空接口與type switch或反射來實現類似的功能

  • 任何一個有返回值的函數都必須以return或panic結尾

  • 函數調用時,其參數的傳遞都是按值傳遞的,也就是說參數接收到的是傳遞的值的副本,有的時候我們可以傳遞引用的副本給參數如Function(&variable),這個時候參數得到的是一個指針的拷貝,但是通過這個指針存儲的值我們也可以操作原始對象的數據

  • 幾乎在任何情況下,傳遞指針的消耗都比傳遞副本來得少

  • 函數的返回值可以有多個,對於返回值的聲明,可以只在函數上聲明返回值的類型,也可以爲每個返回值設置一個名稱。如果爲返回值設置了名稱,需要注意的是,該返回值在進入函數時就相當於聲明瞭一個局部變量,也就是說在函數內不需要再聲明該變量,而可以直接賦值使用,並且這種情況下,函數的return後也可以不接任何的參數,而只需要寫一個return即可,但是爲了代碼的可讀性,強烈建議這種情況也把返回值給寫上。

// 不具名返回值
func getX2AndX3(input int) (int, int) {
	return 2 * input, 3 * input
}
// 具名返回值
func getX2AndX3_2(input int) (x2, x3 int) {
	x2 = 2 * input
	x3 = 3 * input
	return
}
  • 儘量使用命名返回值,這會使代碼更清晰,更簡短,同時更加容易讀懂

  • 對於函數返回值,可以使用空白符_來將某個或某幾個不需要的返回值給忽略掉

  • 變長參數的傳遞指的是在參數列表的最後一位上使用諸如arg ...type的形式傳遞的參數,變長參數的函數聲明形式如下:

func myFunc(a, b string, arg ...int) {}
  • 變長參數本質上就是一個slice,需要注意的是,如果需要將一個slice當做變長參數傳遞給函數,那麼該參數後必須加上...,如:
s := []int{3, 1, 4, 9, 7, 1}
result = min(s...)
fmt.Printf("min num is %d\n", result)
  • type switch結構
func typecheck(val ...interface{}) {
	for _, v := range val {
		switch v.(type) {
		case int:
		case float64:
		case string:
		default:
		}
	}
}
  • defer關鍵字允許我們推遲到函數返回之前(或任意位置執行return語句之後)一刻才執行某個語句或函數
  • defer後面可以使用語句調用,如果使用的是語句調用,那麼傳遞的參數數據會被立即拷貝,而如果其後接的是一個匿名函數,那麼在函數中直接使用的外部數據就是通過地址拷貝來進行處理的,也就是說外部調用過程中對該變量的任何操作都會反映在defer後的匿名函數中
  • 當有多個defer行爲被註冊時,它們會以逆序的順序執行,也就是先註冊的後執行
  • defer關鍵字主要作用是一些函數執行完之後進行的收尾工作
    • 解鎖一個加鎖的資源
    • 打印最終報告
    • 關閉數據庫鏈接
  • 關於defer需要注意的一點是,其只會讓其後的最外層函數或者最外層的語句在函數返回之前調用,而其外層函數或外層語句所需要的參數是會按照聲明的順序直接調用的,如:
// 這裏首先調用tracing("a"),然後調用fmt.Println("in a"),最後再調用untracing()
defer untracing(tracing("a"))
fmt.Println("in a")
  • 關於defer與聲明式返回值,有一點需要說明的是,如果聲明瞭返回值的名稱,而return語句中又返回了另一個值,也就是說return語句返回的值與聲明的返回值變量中的值不一致時,go在調用return語句時,會進行一步操作就是將return語句後的值賦值給聲明的返回值變量中。那麼這裏存在的一個問題是,如果defer語句中修改了聲明的返回值變量,那麼無論return語句中返回的是什麼,最終都是以defer語句中進行的修改爲準,例如:
// 這裏函數最終的返回值是2,因爲return語句中首先將ret置爲1,然後defer語句中將其自增爲2了
func f() (ret int) {
	defer func() {
		ret++
	}()
	
	return 1
}
  • 內置函數
名稱說明
close用於管道通信
len和caplen用於返回某個類型的長度或數量(字符串、數組、切片、map和管道);cap是容量的意思,用於返回某個類型的最大容量(只能用於切片和map)
new和makenew和make均是用於分配內存:new用於值類型和用戶定義的類型,如自定義結構,make用於內置引用類型(切片、map和管道)。它們的用法就像是函數,但是將類型作爲參數:new(type)、make(type)。new(T)分配類型T的零值並返回其地址,也就是指向類型T的指針。它也可以用於基本類型:v := new(int)。make(T)返回類型T的初始化之後的值,因此它比new進行更多的工作,new()是一個函數,不要忘記它的括號
copy和append用於複製和連接切片
panic和recover兩者均用於錯誤處理機制
print和println底層打印函數,在部署環境中建議使用fmt包
complex和real imag用於創建和操作複數
  • 對於沒有名稱的函數,我們稱爲匿名函數,匿名函數是不能獨立存在的,但是可以將其賦值給某個變量

  • 匿名函數同樣被稱之爲閉包:它們被允許調用定義在其他環境下的變量。閉包可使得某個函數捕捉到一些外部狀態,例如:函數被創建時的狀態,另一種表示方式爲:一個閉包繼承了函數所聲明時的作用域。這種狀態(作用域內的變量)都被共享到閉包的環境中,因此這些變量可以在閉包中被操作,直到被銷燬。閉包經常被用作包裝函數:它們預先定義好1個或多個參數以用於包裝。另一個不錯的閉包應用就是使用閉包來完成更加簡潔的錯誤檢查。

  • 一個返回值爲另一個函數的函數可以被稱爲工廠函數,這在我們需要創建一系列相似的函數的時候非常有用:書寫一個工廠函數,而不是針對每種情況都書寫一個函數。

  • 可以返回其他函數的函數和接收其它函數作爲參數的函數均被稱之爲高階函數,是函數式語言的特點。

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