函數(shù)
不支持 嵌套 (nested)于游、重載 (overload) 和 默認(rèn)參數(shù) (default parameter)毁葱。
? 無(wú)需聲明原型。
? 支持不定長(zhǎng)變參贰剥。
? 支持多返回值倾剿。
? 支持命名返回參數(shù)。
? 支持匿名函數(shù)和閉包蚌成。
使用關(guān)鍵字 func 定義函數(shù),左大括號(hào)依舊不能另起一行前痘。
func test(x,y int,s string) (int string) { //類(lèi)型相同的相鄰參數(shù)可合并。
n := x + y //多值返回必須用括號(hào)
return n, fmt.Sprintf(s,n)
}
函數(shù)是第一類(lèi)對(duì)象,可作為參數(shù)傳遞担忧。建議將復(fù)雜簽名定義為函數(shù)類(lèi)型,以便于閱讀清笨。
func test(fn func() int) int {
return fn()
}
type FormatFunc func(s string, x,y int) string //定義函數(shù)類(lèi)型
func format(fn FormatFunc, s string, x,y int) string {
return fn(s,x,y)
}
func main() {
s1 := test(func() int { return 100}) //直接將匿名函數(shù)當(dāng)參數(shù)
s2 := format(func(s string, x, y int) string {
return fmt.Sprintf(s, x, y)
}, "%d, %d", 10, 20)
println(s1, s2)
變參
變參本質(zhì)上就是slice过蹂。只能有一個(gè),且必須是最后一個(gè)參數(shù)位。
func test(s string, n ...int) string {
var x int
for _, i := range n {
x += i
}
return fmt.Sprintf(s, x)
}
func main() {
println(test("sum: %d", 1, 2, 3))
}
使用slice對(duì)象做變參時(shí)翘盖,必須展開(kāi)督赤。
func main() {
s := []int{1, 2, 3}
println(test("sum: %d",s...))
}
返回值
不能用容器對(duì)象接收多返回值霉颠。只能用多個(gè)變量猬仁,或“_”忽略。多個(gè)返回值可直接作為其他函數(shù)調(diào)用實(shí)參轧房。
func test() (int, int) {
return 1, 2
}
func add(x, y int) int {
return x + y
}
func sum(n ...int) int {
var x int
for _, i := range n {
x += i
}
return x
}
func main() {
println(add(test()))
println(sun(test()))
}
命名返回參數(shù)可看做與形參類(lèi)似的局部變量,最后由 return 隱式返回拌阴。
func add(x, y int) (z int) {
z = x + y
return
}
func main() {
println(add(1, 2))
}
命名返回參數(shù)可被同名局部變量遮蔽,此時(shí)需要顯式返回。
func add(x, y int) (z int) {
{// 不能在一個(gè)級(jí)別,引發(fā) "z redeclared in this block" 錯(cuò)誤奶镶。
var z = x + y
// return // Error: z is shadowed during return
return z // 必須顯式返回迟赃。
}
}
命名返回參數(shù)允許 defer 延遲調(diào)用通過(guò)閉包讀取和修改陪拘。
func add(x, y int) (z int) {
defer func() {
z += 100
}()
z = x + y
return
}
func main() {
println(add(1, 2)) //輸出:103
}
顯式 return 返回前,會(huì)先修改命名返回參數(shù)。
func add(x, y int) (z int) {
defer func() {
println(z) //輸出:203
}()
z = x + y
return z + 200
}
func main() {
println(add(1, 2)) //輸出:203
}
匿名函數(shù)可賦值給變量,做為結(jié)構(gòu)字段,或者在 channel 里里傳送纤壁。閉包復(fù)制的是原對(duì)象指針,這就很容易解釋延遲引用現(xiàn)象藻丢。
延遲調(diào)用
關(guān)鍵字 defer 用于注冊(cè)延遲調(diào)用。這些調(diào)用直到 ret 前才被執(zhí)行摄乒,通常用于釋放資源或錯(cuò)誤處理。多個(gè) defer 注冊(cè)残黑,按 FILO 次序執(zhí)行馍佑。哪怕函數(shù)或某個(gè)延遲調(diào)用發(fā)生錯(cuò)誤,這些調(diào)用依舊會(huì)被執(zhí)行梨水。
濫用 defer 可能會(huì)導(dǎo)致性能問(wèn)題,尤其是在一個(gè) "大循環(huán)" 里拭荤。
var log sync.Mutex
func test() {
lock.Lock()
lock.Unlock()
}
func testdefer() {
lock.Lock()
defer lock.Unlock()
}
func BenchmarkTest(b *testging.B) {
for i := 0; i < b.N; i++ {
test()
}
}
func BenchmarkTestDefer(b *testging.B) {
for i := 0; i < b.N; i++ {
testdefer()
}
}
//輸出:
BenchmarkTest 50000000 43 ns/op
BenchmarkTestDefer 20000000 128 ns/op
錯(cuò)誤處理
沒(méi)有結(jié)構(gòu)化異常,使用panic拋出錯(cuò)誤疫诽,recover捕獲錯(cuò)誤舅世。由于 panic、recover 參數(shù)類(lèi)型為 interface{},因此可拋出任何類(lèi)型對(duì)象奇徒。捕獲函數(shù) recover 只有在延遲調(diào)用內(nèi)直接調(diào)用才會(huì)終止錯(cuò)誤,否則總是返回 nil雏亚。任何未
捕獲的錯(cuò)誤都會(huì)沿調(diào)用堆棧向外傳遞。
func test() {
defer func() {
if err := recover(); err != nil {
println(err.(string)) // 將interface{}轉(zhuǎn)型為string類(lèi)型
}()
panic("panic erro!")
}
除用 panic 引發(fā)中斷性錯(cuò)誤外,還可返回 error 類(lèi)型錯(cuò)誤對(duì)象來(lái)表示函數(shù)調(diào)用狀態(tài)摩钙。標(biāo)準(zhǔn)庫(kù) errors.New 和 fmt.Errorf 函數(shù)用于創(chuàng)建實(shí)現(xiàn) error 接口的錯(cuò)誤對(duì)象罢低。通過(guò)判斷錯(cuò)誤對(duì)象實(shí)例來(lái)確定具體錯(cuò)誤類(lèi)型。如何區(qū)別使用 panic 和 error 兩種方式?
慣例是:導(dǎo)致關(guān)鍵流程出現(xiàn)不可修復(fù)性錯(cuò)誤的使用 panic,其他使用 error胖笛。