Go語言 函式

2021-07-24 18:32:16 字數 4908 閱讀 7324

函式是結構化程式設計的最小模組單元,使用關鍵字『func』定義函式。go語言定義函式的一些特點總結如下:

- 無需前置宣告

- 不支援命名巢狀定義

- 不支援同名函式過載

- 不支援預設引數

- 支援不定長變參

- 支援多返回值

- 支援命名返回值

- 支援匿名函式和閉包

函式屬於第一類物件,具備相同簽名(引數及返回值型別)的視為同一型別。

定義乙個函式:

func test(x int,s string)int{} //其中func為關鍵字,test為函式名,(x int,s string)為引數列表,int為返回值型別

package main

import(

"fmt"

)func hello()

func main()

函式只能判斷其是否為nil,不支援其它比較操作,從函式返回區域性變數指標是安全的。

package main

import(

"fmt"

)func test()*int

func main()

輸出:

0xc04203e1d0 10

go語言不支援有預設值得可選引數,不支援命名實參。呼叫時,必須按簽名順序傳遞指定型別和數量的實參,就算以「_」忽略的也不能省略掉。

不管是指標、引用型別,還是其他型別引數,都是值拷貝傳遞。如果函式引數過多,建議將其定義為乙個復合結構型別。

變參本質上就是乙個切片。只能接受乙個到多個同型別引數,並且放在列表尾部。

package main

import(

"fmt"

)func test(s string,a ...int)

func main()

輸出:

adb,int,[1 2 3 4]

既然變參是切片,那麼引數複製的僅是切片自身,並不包含底層陣列,因此可修改原資料。如果需要可使用內建函式copy複製底層資料。

package main

import(

"fmt"

)func test(a ...int)

}func main()

test(a...)

fmt.println(a)

}

輸出:

[11 12 13 14]

有返回值得函式必須有明確的return語句,除非有panic或者無break的死迴圈則無需return語句。

package main

import(

"fmt"

"errors"

)func test(x,y int)(int,error)

return x/y ,nil

}func main()else

}

輸出:

0 使用命名返回值,可直接使用return隱式返回,如果返回值型別能明確表明其含義,就盡量不要對其命名

package main

import(

"fmt"

"errors"

)func test(x,y int)(a int,err error)

a = x/y

return

}func main()else

}

輸出:

can not be zero

匿名函式是指沒有定義名字的函式。除沒有名字外,匿名函式和普通函式完全相同。最大的區別是我們可在函式內部定義匿名函式,形成類似巢狀效果。匿名函式可直接呼叫,儲存到變數,作為引數或返回值。

直接執行

package main

import(

"fmt"

)func main()("hello word")

}

輸出:

hello word

賦值給變數

package main

import(

"fmt"

)func main()

fmt.println(add(1

,2))

}

輸出:

3作為引數:

package main

import(

"fmt"

)func test(f func())

func main())

}

輸出:

hello

作為返回值

package main

import(

"fmt"

)func test() func(int,int)int

}func main()

輸出:

3 普通函式和匿名函式都可以作為結構體欄位,或經通道傳遞。不曾使用的匿名函式會被編譯器當做錯誤。

閉包

閉包(closure)是在其詞法上下問引用了自由變數的函式,或者說是函式和其引用的環境組合體。

package main

import(

"fmt"

)func test(x int) func()

}func main()

輸出:123

就以上**而言,test返回的匿名函式會引用上下文環境變數x。當該函式在main中執行時,它依然可正確讀取x的值,這種現象就稱作閉包。閉包直接引用了原環境變數。

正因為閉包通過指標引用環境變數,那麼可能會導致其生命週期延長,甚至被分配到堆內。解決的辦法就是每次用不同的環境變數或傳參複製,讓各自閉包環境各不相同。

語句defer向當前函式註冊稍後執行的函式呼叫。這些函式被稱作延遲呼叫,因為它們直到當前函式函式執行結束前才被執行,常用語資源釋放、解除鎖定、以及錯誤處理等操作。

func main()

defer f.close() //僅註冊,直到mian函式退出之前才執行

...do something...

}

注意:延遲呼叫註冊的是呼叫,必須提供執行所需引數(哪怕為空)。引數值在註冊時被複製並快取起來。如對狀態敏感,可改用指標或閉包。

package main

import(

"fmt"

)func main()(x)

x +=10

y +=20

fmt.println(x,y)

}

輸出:

11 22

defer x,y = 1 22

延遲呼叫可修改當前函式命名返回值,但其自身返回值被拋棄,多個延遲註冊按filo次序(先進後出)執行。

error

官方推薦的標準做法是返回error狀態

func test(a …inte***ce{})(n int,err error)

標準庫將error定義為介面型別,以便實現自定義錯誤型別。按照慣例,error總是最後乙個返回引數。標準庫提供了相關建立函式,可方便的建立包含簡單錯誤文字的error物件。

package main

import(

"fmt"

"errors"

)func test(x,y int)(a int,err error)

a = x/y

return

}func main()else

}

某些時候我們需要自定義錯誤型別,以容納更多上下文狀態資訊。這樣做還可以基於型別做出判斷

package main

import(

"fmt"

)type diverror struct

func (diverror) error() string

func div(x,y int)(int,error) //返回自定義錯誤型別

}return x/y,nil

}func main()

}fmt.println(z)

}

輸出:

division by zero 5 0

-1panic,recover

與error相比,panic/recover在使用方法更接近try/catch結構化異常。但是它們是內建函式而非語句。panic會立即中斷當前函式流程,執行延遲呼叫。而在延遲呼叫函式中recover可捕獲並返回panic提交的錯誤物件。

func main()

}()panic("dead") //引發錯誤

fmt.println("exit") //永不會執行

}

因為panic引數是空介面型別,因此可使用任何物件作為錯誤狀態。而recover返回結果同樣要做轉型才能獲得具體資訊。

無論是否執行recover,所有延遲呼叫都會被執行。但中斷性錯誤會沿用堆疊向外傳遞,要麼被外層捕獲,要麼程序崩潰。連續的呼叫panic,僅最後乙個會被recover捕獲。

在延遲函式中panic,不會影響後續延遲呼叫執行。而recover之後panic,可被再次捕獲。另外,recover必須在延遲呼叫 函式中執行才能正常工作。

建議:除非是不可恢復性、導致系統無法正常工作的錯誤,否則不建議使用panic

Go語言函式

go語言函式function go函式不支援巢狀 過載和預設引數 但支援以下特性 無需宣告原型 不定長度引數 多返回值 命名返回值引數 匿名函式 閉包 定義函式使用關鍵字func,且左大括號不能另起一行 函式也可以作為一種型別使用 不定引數 不定引數的傳遞 任意型別的不定引數 如果你希望傳任意型別的...

Go 語言函式

func function name parameter list return types parameter list 引數列表,引數就像乙個佔位符,當函式被呼叫時,你可以將值傳遞給引數,這個值被稱為實際引數。引數列表指定的是引數型別 順序 及引數個數。引數是可選的,也就是說函式也可以不包含引數...

Go語言函式

和c語言一樣,go語言也有函式,在go中函式用func關鍵字標識,其定義格式如下 func 函式名 引數1 引數2 返回值1 返回值2 比較有特色的地方是go語言可以返回多個返回值。package main import fmt func intsum1 x,y int int func intsu...