天天看點

Go語言學習筆記(四)Go語言函數1.普通函數的聲明形式2.同一類型傳回值3.帶有變量名的傳回值4.參數傳遞5.函數變量6.匿名函數7.變參函數8.defer(延遲執行語句)

        Go語言的函數聲明以func辨別,後面緊接着函數名、參數清單、傳回參數清單以及函數體。

1.普通函數的聲明形式

func 函數名(參數清單) (傳回參數清單){
    //函數體
}

注意:
在同一個包内,函數名不能相同
參數清單中如果多個參數類型相同,則可放在一起聲明。如func test(a, b int) {}同時聲明a, b為int類型
函數可以同時傳回多個值
           

2.同一類型傳回值

func typedTwoValues() (int, int) {
    return 1, 2
}

a, b = typedTwoValues()
fmt.Println(a, b)
           

3.帶有變量名的傳回值

func namedRetVallues() (a, b int) {
    a = 1
    b = 2
    return
}

當函數使用命名傳回值時,可以在return中不填寫傳回值清單,如果填寫也是可行的。
           

4.參數傳遞

        Go語言中傳入和傳回參數在調用和傳回時都使用值傳遞,這裡要注意的是指針、切片和map等引用型對象指向的内容在參數傳遞中不會發生複制,而是将指針進行複制,類似于建立一次引用。

5.函數變量

        在Go語言中,函數也是一種類型,可以和其他類型一樣被儲存在變量中。

func fire() {
    fmt.Println("call fire")
}

func foo1(a int) int{

}

var f1 func()   //定義函數變量f,無參無傳回值
f1 = fire

var f2 func(int) int = foo1
           

6.匿名函數

        Go語言支援匿名函數,即在需要使用函數時,再定義函數,匿名函數沒有函數名,隻有函數體,函數可以被作為一種類型指派給函數類型的變量,匿名函數也往往以變量方式被傳遞。

        匿名函數經常被用于實作回調函數、閉包等。

(1)匿名函數定義格式

func(函數清單) (傳回參數清單) {
    //函數體
}
           

(2)定義時調用匿名函數

func(data int) {
    fmt.Println("hello", data)
}(100)
           

(3)将匿名函數指派給變量

f := func(data int) {
    fmt.Println(data)
}

f(100)     //調用匿名函數


           

(4)匿名函數作為回調函數

func visit(list []int, f func(int)){
    //to do
    for _, v := range list {
        f(v)
    }
}

visit([]int{1, 2, 3}, func(data int) {
    fmt.Println(data)
})

           

(5)匿名函數實作操作封裝

var skill = map[string]func() {
    "fire":func() {
        fmt.Println("chicken fire")
    },
    "run":func() {
        fmt.Println("soldier run")
    },
}
           

7.變參函數

        所謂可變參數,是值參數數量不固定的函數形式。Go語言支援可變參數特性,函數聲明和調用時沒有固定數量的參數。

(1)變參函數定義格式

func 函數名(固定參數清單, v ... T) (傳回參數清單) {
    //todo
}

可變參數一般被放置函數清單的末尾,前面是固定參數清單
v為可變參數變量,類型為[]T
T為可變參數的類型,如果T為interface{},傳入的可以是任意類型

           

(2)所有參數都是可變參數

以fmt.Println()為例:
func Println(a ...interface{}) (n int, err error) {
    return Fprintln(os.Stdout, a...)
}
           

(3)部分參數是可變參數

以fmt.Printf()函數為例:

func Printf(format string, a ...interface{}) (n int, err error) {
    return Fprintf(os.Stdout, format, a...)
}
           

(4)在多個可變參數函數中傳遞參數

func rawPrint(rawList ...interface{}) {
    //todo
}

func Print(slist ...interface{}) {
    rawPrint(slist...)    //這種用法在切片的append()中也見過
}

func main() {
    Print("hello", 123)
}
           

8.defer(延遲執行語句)

       Go語言的defer語句會将其後面跟随的語句進行延遲處理。在defer歸屬的函數即将傳回時,将延遲處理的語句按defer的逆序進行執行。也就是說,先被defer的語句最後被執行,最後被defer的語句,最先被執行。

func main() {
    
    defer fmt.Println("defer begin")

    defer fmt.Println(1)

    defer fmt.Println(2)

    defer fmt.Println(3)

    defer fmt.Pritnln("defer end")
}

輸出結果:
defer begin
defer end
3
2
1

通過defer聲明調用的函數的調用順序和C++析構的調用函數類似,都是一個棧的調用順序、