go函式定義格式如下:
func
function_name
([parameter list]
)[return_types]
例如:
func
add(n1, n2 int
)int
go可以很靈活的建立函式,並作為另外乙個函式的實參:
type gettownumberresultfunc func
(int
,int
)int
func
add(n1, n2 int
)int
func
printresult
(n1, n2 int
,f gettownumberresultfunc)
func
main()
printresult(10
,20,mygetreslut)
}
go支援匿名函式,可作為閉包,匿名函式是乙個"內聯"語句或表示式,匿名函式的優點在於可以直接使用函式內的變數。
type gettownumberresultfunc func
(int
,int
)int
func
getaddfunc()
func
(int
,int
)int
}func
printresult
(n1, n2 int
,f gettownumberresultfunc)
func
main()
go函式中只有值傳遞(比較特殊的是,go語言閉包函式對外部變數是以引用的方式使用),引數傳遞時會複製物件,要麼是值的拷貝,要麼是指標的拷貝(slice,map,channel,函式,指標),如果引數型別是指標,則函式可以通過該引數影響原有物件。
當引數為inte***ce型別時,如果實參的實現有指標接受者方法時,引數只能用指標不能用值。
type heightsetter inte***ce
type person struct
func
(person *person)
setheight1
(height int
)func
(person person)
setheight2
(height int
)func
zeroheight
(heightsetter heightsetter)
func
main()
//zeroheight(person) person does not implement heightsetter (setheight1 method has pointer receiver)
zeroheight
(&person)
//正確
}
go函式還支援可變數量的引數,可變數量的引數必須是最後出現的引數,可變數量的引數其實是乙個切片型別的引數。
package main
import
"fmt"
func
printstrings
(tag int
,strs ...
string)}
func
printvalues
(tag int
,values ...
inte***ce
)func
main()
hello
world
hello world
go函式可以返回多個值,這個時候返回值型別要用括號括起來,例如:
func
div(n1, n2 int)(
int,
int)
go函式可以給返回值命名,這個時候即使只有乙個返回值也要用括號括起來,例如:
func
add(n1, n2 int
)(result int
)
func
div(n1, n2 int
)(result int
,remainder int
)
關鍵字defer後面的語句會在函式退出之前呼叫,如果有多個defer表示式,呼叫順序類似於棧,越後面的defer表示式越先被呼叫。
在defer表示式中可以通過修改命名返回值改變最終返回值,而以區域性變數作為返回值時則不會影響,因為函式會先將區域性變數賦值給返回值,然後呼叫defer表示式,這個時候在defer表示式修改區域性變數也改變不了返回值。
func
testfunc1
(n int
)int()
return result
}func
testfunc2
(n int
)(result int)(
)return
}func
main()
recover用於捕捉panic丟擲的異常資訊,recover必須在defer函式中執行,defer函式必須定義在panic之前,直接defer呼叫recover無效。
func
main()
下面**中recover執行在普通函式中,所以也是無效的。
func
main()
()}(
)panic(1
)}
go沒有物件導向,但卻可以給指定型別新增方法,格式如下:
func
(variable_name variable_data_type)
function_name()
[return_type]
go中的方法就是乙個包含了接受者的函式,接受者可以是型別的乙個值或是乙個指標,類似於c++中的this。
在呼叫方法的時候,值型別既可以呼叫值接收者的方法,也可以呼叫指標接收者的方法;指標型別既可以呼叫指標接收者的方法,也可以呼叫值接收者的方法。
如果方法的接收者是值型別,無論呼叫者是物件還是物件指標,修改的都是物件的副本,不影響呼叫者;如果方法的接收者是指標型別,則呼叫者修改的是指標指向的物件本身。
type person struct
func
(person person)
printheight()
func
(person *person)
setheight1
(height int
)func
(person person)
setheight2
(height int
)func
main()
person.
setheight1
(200
) person.
printheight()
//200
person.
setheight2
(300
) person.
printheight()
//200
}
利用方法值和方法表示式可以將方法轉換為普通函式。
package main
type person struct
func
(person person)
printheight()
func
main()
//方法表示式
normalfunc1:=
(*person)
.printheight//func printheight(person *person)
normalfunc1
(&person)
//方法表示式
normalfunc2:=
(person)
.printheight//func printheight(person person)
normalfunc2
(person)
//方法值
normalfunc3:=person.printheight
normalfunc3()
}
go語言函式的遞迴呼叫深度邏輯上沒有限制,函式呼叫的棧是不會出現溢位錯誤的,因為go語言執行時會根據需要動態地調整函式棧的大小。每個goroutine剛啟動時只會分配很小的棧(4或8kb,具體依賴實現),根據需要動態調整棧的大小,棧最大可以達到gb級。
在go1.4以前,go的動態棧採用的是分段式的動態棧,通俗地說就是採用乙個鍊錶來實現動態棧,每個鍊錶的節點記憶體位置不會發生變化。但是鍊錶實現的動態棧對某些導致跨越鍊錶不同節點的熱點呼叫的效能影響較大,因為相鄰的鍊錶節點它們在記憶體位置一般不是相鄰的,這會增加cpu快取記憶體命中失敗的機率。
為了解決熱點呼叫的cpu快取命中率問題,go1.4之後改用連續的動態棧實現,也就是採用乙個類似動態陣列的結構來表示棧。不過連續動態棧也帶來了新的問題:當連續棧動態增長時,需要將之前的資料移動到新的記憶體空間,這會導致之前棧中全部變數的位址發生變化。
雖然go語言執行時會自動更新引用了位址變化的棧變數的指標,但最重要的一點是要明白go語言中指標不再是固定不變的了(因此不能隨意將指標保持到數值變數中,go語言的位址也不能隨意儲存到不在gc控制的環境中,因此使用cgo時不能在c語言中長期持有go語言物件的位址)。
golang學習筆記 函式
不定引數型別函式定義 args type package main import fmt func func01 a byte,args int func main 輸出 len arg is 3 a is c 定義函式型別 package main import fmt func add a,b ...
Golang學習筆記 九 函式
什麼是函式?函式是乙個打包好的語句序列單元,我們將多個語句邏輯定義成為乙個函式,這樣方便我們在程式中多次呼叫,而在golang語言,函式更是一等公民,在我們的開發中隨處可見。乙個函式,由關鍵字func 函式名 形參列表,返回值列表和函式體五個部分組成,格式如下 func name arg int e...
Golang學習筆記 09 函式
函式是基本的 塊,用於執行乙個任務。go 語言最少有個 main 函式。通過函式來劃分不同功能,邏輯上每個函式執行的是指定的任務。函式宣告告訴了編譯器函式的名稱,返回型別,和引數。go 語言標準庫提供了多種可動用的內建的函式。例如,len 函式可以接受不同型別引數並返回該型別的長度。如果我們傳入的是...