認真一點學 Go:10. 函式

printlove發表於2021-09-30

原文連結:mp.weixin.qq.com/s/0TawtUd-sh27Ves...

學到什麼

  1. 如何呼叫函式?

  2. 如何建構函式?

  3. 函式如何返回多個值?

  4. 如何構造匿名函式?

  5. 如何傳遞函式?

  6. 內建函式有哪些?

介紹

函式是基本的程式碼塊,它負責將一個複雜問題分解為不同的函式提供呼叫與複用。

編寫函式時,無需關注順序,因為 Go 語言是編譯型的。

在 Go 語言中有三種函式型別:

  • 基本格式:有命名的函式,直接呼叫完事。

  • 匿名函式:沒有名字的函式。

  • 結構體攜帶的函式:也可以稱之為方法,後續結構體再展開講解。

基本格式


func Fun1(arg1 T, arg2 T) T {

        ...

        return r1

}
  • Fun1 為自定義的函式名稱。

  • arg1arg2 為自定義引數名稱,宣告瞭兩個引數,可以再增加。

  • T 代表 Go 語言中的任意型別,使用時替換成 int、string、slice 等等型別。

  • 小括號後緊跟函式返回值型別。

  • return 為函式返回的關鍵字,攜帶要返回的值,函式內之後的邏輯將不會執行。

  • 函式體的第一個花括號必須緊跟在函式後。

舉例:


// 計算兩個數之和並且返回

func AddNum(n1 int, n2 int) int {

    return n1 + n2

}

函式也可以沒有返回值,這個時候就無需 return 關鍵字,例如: main() 入口函式、 init() 初始化函式。

當函式體內出現了 panic 函式,用於丟擲異常,這時如果定義了返回型別, return 關鍵字就可以選擇省略。

返回多個值

Go 語言函式中有個特點,可以多個值返回。在宣告返回值型別時,可以不指定名稱,也可以指定名稱,啥意思呢,往下看。

1. 無名稱


func Fun1(arg1 T, arg2 T) (T, T) {

        ...

        return r1, r2

}

和“基本格式”的不同點:

  • 當需要返回至少兩個值時,返回型別需要用小括號包裹,以逗號分隔。

  • 使用 return 攜帶多個返回值。

2. 有名稱


func Fun1(arg1 T, arg2 T) (n1 T, n2 T) {

        ...

        return

}
  • 返回值型別指定了名稱後,在 return 返回時,可以不帶值,當然也可以都帶上。

  • 當有了名稱,即使是 1 個返回型別,也需要用小括號包裹。

為什麼有了名稱 return 就不用攜帶值呢?

因為相當於在返回時,初始化好了返回值,例如上面的格式中 n1n2 就是初始化的兩個變數,在函式運算中,只要將返回結果存入 n1n2 中,不存就按照初始化返回,當然也可以 return 攜帶值。

函式呼叫

構造好一個函式後,如何呼叫,格式如下:


r1, r2 := Fun1(param1, param2)

呼叫時傳遞了兩個引數,返回時接受兩個返回值。

如果接受多個值時,某個值我不想使用時,是不能擱置在那的,不然編譯器會報錯,需要使用下劃線 “_” 替代,表示我不用。


r1, _ := Fun1(param1, param2)

匿名函式

匿名函式就是在建構函式時,函式沒有名稱,想呼叫時,需要把匿名函式賦值給一個變數,或者在構造時直接呼叫。

1. 賦值給變數


fun1 := func (arg1 T, arg2 T) T {

        ...

        return r1

}

賦值後, fun1 就是一個函式型別的變數, 呼叫格式:fun1(param1, param2)

2. 構造時呼叫


func (arg1 T, arg2 T) T {

        ...

        return r1

}(param1, param2)

在建構函式時,花括號後緊跟引數傳遞(param1, param2),不需要賦值給一個變數,直接構造後馬上呼叫。

傳遞函式

在 Go 語言中,函式是“一等公民”,它和 int 、string 等等,都是一個級別,可以作為引數進行傳遞。

舉例:


// function/deliver.go

package main

// callback 是一個函式型別引數

func Calc(callback func(n1 int, n2 int) int) int {

    x, y := 3, 4

    return callback(x, y)

}

// 計算兩數之積

func Mul(n1 int, n2 int) int {

    return n1 * n2

}

func main() {

    // 第一個:傳遞一個匿名函式

    Calc(func(n1 int, n2 int) int {

        return n1 + n2

    })

    // 第二個:傳遞一個定義好的函式

    Calc(Mul)

}

分別演示了兩種函式的傳遞方式,第一個匿名函式計算兩數之和,第二個用定義好的函式計算兩數之積。當然傳遞函式不止是通過引數,也可以是函式返回值、切片元素儲存、map值儲存等等。

宣告函式型別

宣告函式型別,意思就是可以自定義一個函式型別,給這個函式取一個別名,像例如 int 一樣很方便的去宣告變數或者引數型別。


type CallbackFunc func(n1 int, n2 int) int

現在自定義了一個名為 CallbackFunc 的函式型別,下來看如何使用:


func Calc(callback CallbackFunc) int {

...

}

Calc 函式有一個函式引數,這個引數的型別名稱為 CallbackFunc

函式引數

1. 引數型別省略

在宣告函式引數時,有時候會遇到連續宣告多個相同型別,這個時候,就可以只保留一個型別名稱。


// 沒精簡的

func Fun1(arg1 string, arg2 int, arg3 int)

// 精簡後

func Fun1(arg1 string, arg2, arg3 int)

精簡後, arg2 引數後省略了 int,這樣就和它後面的引數型別一致。

2. 值傳遞與引用傳遞

我們先定下引數稱呼,函式呼叫時傳遞的引數稱為實參,建構函式時的引數稱為形參。

在 Go 語言中,切片(slice)、map、介面(interface)、通道(channel)這樣的引用型別都是預設使用引用傳遞,在函式內修改形參是會改變實參的值。

對於切片,有種情況會打破引用傳遞這個規律,具體可以看看 《內建結合 - 切片》這篇文章。

對於其它剩下的型別,預設都是值傳遞,函式接收到的形參只是副本,函式內對形參的更改是不會影響到實參的。

如果希望更改實參的值,可以傳遞指標,在實參前增加“&”符號,表示取實參的地址,例如: Fun1(&param)

3. 變長引數

當建構函式時,函式的最後一個引數是 ...T 形式時,稱為變長引數,它可以接受至少 0 個資料。


// 一個固定引數,一個變長引數

// nums 實際是一個切片

func Func1(str string, nums ...int) {

    ...

}

呼叫例子如下:


// 沒傳遞變長引數

Func1("miao")

// 給變長引數傳遞不同數量的值

Func1("miao", 1)

Func1("miao", 1, 2)

當把一個切片型別傳遞給可變引數時,在切片後跟著 ... 三個點,傳遞給變長引數,表示將切片元素展開。


nums := []int{1, 2, 3}

Func1("miao", nums...)

內建函式

在 Go 語言中,有一些函式無需匯入任何包就可以使用,下來對這些函式簡要說明一下。

總共 15 個內建函式,如下:

  1. make:為切片,map、通道型別分配記憶體並初始化物件。

  2. len:計算陣列、切片、map、通道的長度。

  3. cap:計算陣列、切片、通道的容量。

  4. delete:刪除 map 中對應的鍵值對。

  5. append:將資料新增到切片的末尾。

  6. copy:將原切片的資料複製到新切片中。

  7. new:除切片、map、通道型別以外的型別分配記憶體並初始化物件,返回的型別為指標。

  8. complex:生成一個複數。

  9. real:獲取複數的實部。

  10. imag:獲取複數的虛部

  11. print:將資訊列印到標準輸出,沒有換行。

  12. println:將資訊列印到標準輸出並換行。

  13. close:關閉通道。

  14. panic:觸發程式異常。

  15. recover:捕捉 panic 的異常資訊。

總結

本篇我對 Go 語言中的函式進行了系統的講解,也列舉了 15 個內建函式。對於內建函式的使用,有的在前面文章使用過,有的還沒有,先做一個整體的瞭解,等到了用的時候再詳查。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章