日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

一文帶你熟悉Go語言中函數的使用_Golang

作者:陳明勇 ? 更新時間: 2022-12-26 編程語言

函數

函數的英文單詞是 Function,這個單詞還有著功能的意思。在 Go 語言中,函數是實現某一特定功能的代碼塊。函數代表著某個功能,可以在同一個地方多次使用,也可以在不同地方使用。因此使用函數,可以提高代碼的復用性,減少代碼的冗余。

函數的聲明

通過案例了解函數的聲明有哪幾部分:

定義一個函數,實現兩個數相加的功能,并將相加之后的結果返回。

func Add(num1 int, num2 int) int {
    var sum int
    sum += num1
    sum += num2
    return sum
}

通過案例可以發現,函數的聲明有5部分:

1、關鍵字

函數的關鍵字是 func,聲明函數必須以 func 關鍵字開始。

2、函數名

Go 推薦使用駝峰命名的方式,和變量的命名規則一樣,首字母大寫的函數名可以在包外訪問,小寫的只能在包內訪問。

3、參數列表

參數列表中聲明了在函數體里所使用到的變量。參數列表位于函數名后面,用括號包裹著,多個參數使用逗號分隔開。

4、返回值列表

返回值為函數執行后的一個結果,上述代碼只有一個返回值,如果有多個返回值,需要用括號包裹著,返回值之間用逗號分隔開。

少數情況下,我們會聲明返回值的的名稱如 func Add(num1 int, num2 int) sum int {},多數情況下是不用聲明返回值的名稱的。

5、函數體

大括號內就是函數體,存放著函數的具體實現。 函數的第 34 部分可有可無,也就是說一個函數可以沒有參數和返回值。

Go 函數支持變長參數

在上面的案例中,實現的功能是對兩數求和,如果我們需要對多個數求和,但又不知道具體的數量,函數的參數該怎么聲明呢?這時可以聲明變長參數去接收多個參數。

func main() {
    sum := Add(1, 2, 3, 4)
    println(sum) // 10
}

func Add(nums ...int) int {
    var sum int
    for _, num := range nums {
	sum += num
    }
    return sum
}

變長參數作為形式參數可以接收不定的實際參數,聲明變長參數需要在類型面前加上 ... 。可變參數實際上是一個切片,可以通過 for-range 去操作。

匿名函數

通常情況下,如果一個函數只使用一次,我們就可以定義成匿名函數。

func main() {
    // 定義匿名函數,直接調用
    result := func(num1, num2 int) int {
	return num1 + num2
    }(1, 2)
    println(result)
    // 2、將匿名函數賦值給一個變量,由變量調用
    resultFunc := func(num1, num2 int) int {
	return num1 + num2
    }
    println(resultFunc(1, 2))
}

聲明函數時,不指定函數名的函數,叫做匿名函數。匿名函數可以直接調用,也可以通過賦值給變量,由變量調用。

閉包

閉包就是一個函數和其相關引用環境組合的一個整體。

import "fmt"

// 返回值為一個匿名函數
func getSum() func(int) int {
    var sum int = 0
    // 匿名函數
    result := func(num int) int {
	sum += num
	return sum
    }
    return result
}

func main() {
    f := getSum()
    fmt.Println(f(1)) // 1
    fmt.Println(f(2)) // 3
}
  • 閉包的本質就是一個匿名函數,匿名函數里使用了定義它的函數(getSum)里面的變量 sum,就組成了閉包。
  • 由上述代碼可知,匿名函數中所引用的變量 sum 會一直保存在內存中。

init 函數

每個 go 文件都可以包含一個 init 函數,它是一個初始化函數,用于進行初始化的操作。

var print = getNum()

func getNum() int {
    println("初始化變量")
    return 1
}

func main() {
    println("main...")
}

func init() {
    println("init...")
}

執行結果:

初始化變量
init...
main...

  • 根據執行結果可知,它們的執行順序為:全局變量 → init 函數 → main 函數。
  • 多個 go 文件都有 init 函數時,執行順序為:先執行所導入的模塊的 init 函數,再執行本文件的 init 函數。

函數參數詳解

形式參數與實際參數

在函數聲明的地方,參數列表中的參數被稱為形式參數,簡稱形參;而在函數調用的時候所傳遞的參數被稱為實際參數,簡稱實參。舉例說明:

func main() {
    sum := Add(1, 2)
    println(sum) // 3
}
func Add(num1 int, num2 int) int {
    var sum int
    sum += num1
    sum += num2
    return sum
}

Add 后面的參數被稱為形參,而在 main 方法里,12 被稱為實參。

值傳遞

基本數據類型和數組作為實參時,默認是按 值傳遞,即進行值拷貝,在函數內修改它們的值,原來的值不會改變。舉例說明:

func main() {
    num1, num2 := 1, 2
    Swap(1, 2)
    fmt.Printf("main 函數體內打印:num1: %d, num2: %d", num1, num2)
}

func Swap(num1 int, num2 int) {
    num2, num1 = num1, num2
    fmt.Printf("Swap 函數體內打印:num1: %d, num2: %d\n", num1, num2)
}

執行結果:

Swap 函數體內打印:num1: 2, num2: 1
main 函數體內打印:num1: 1, num2: 2

Swap 函數內,num1num2 的值已經相互交換,但是在 main 函數里,num1num2 的值沒有發生變化。

func main() {
    nums := [3]int{0, 1, 2}
    Swap(nums)
    fmt.Println("main 函數體內打印:nums: ", nums)
}

func Swap(nums [3]int) {
    nums[0] = 1
    fmt.Println("Swap 函數體內打印:nums: ", nums)
}

同樣傳遞數組,在函數內修改數組的值,原數組的值并不會改變。 前面的文章有對指針進行了介紹,指出了通過 * 操作符,可以對指針所指向的變量的值進行修改,因此如果我們想要在函數內改變外部傳過來的參數的值,函數聲明時,形參類型指定為指針類型。

func main() {
    num1, num2 := 1, 2
    Swap(&num1, &num2)
    fmt.Printf("main 函數體內打印:num1: %d, num2: %d", num1, num2)
}

func Swap(num1 *int, num2 *int) {
    *num2, *num1 = *num1, *num2
    fmt.Printf("Swap 函數體內打印:num1: %d, num2: %d\n", *num1, *num2)
}

執行結果:

Swap 函數體內打印:num1: 2, num2: 1
main 函數體內打印:num1: 2, num2: 1

通過結果可知,使用指針變量作為形參,在函數里是可以改變外部的參數的值的。

函數是一種數據類型

Go 里面,函數是一種數據類型,因此函數還可以有很多用法,如創建一個函數變量、將函數作為函數的形參,將函數作為函數的返回值等。

創建函數變量

func main() {
    // 創建函數變量
    hl := Hello
    fmt.Printf("%T\n", hl) // func(string)
    hl("cmy")
}

func Hello(name string) {
    fmt.Printf("Hello %s", name)
}

創建一個函數變量 hl,打印 hl 的類型 → func(string),通過 hl 變量調用函數。

作為函數的形參

import "fmt"

func main() {
    Print("cmy", Hello)
}

func Hello(name string) {
    fmt.Printf("Hello %s", name)
}

func Print(name string, f func(string)) {
    f(name)
}

定義函數 Print ,聲明兩個參數,一個參數是 name,為 string 類型的,另一個參數是 f,為函數類型。傳入 cmyHello 函數,由 Print 函數去執行 Hello 函數。

作為函數的返回值

import "fmt"

func main() {
    f := Print()
    f()
}

func Print() func() {
    return func() {
	fmt.Println("Hello,World!")
    }
}

通過Print 函數返回一個匿名函數函數,這個匿名函數的功能是輸出 Hello,World!,使用 f 變量接收這個函數并調用。

基于函數自定義類型

type AddHandleFunc func(num1, num2 int) int

func main() {
    sum := GetSum(1, 2, Add)
    println(sum)
}

func Add(num1, num2 int) int {
    return num1 + num2
}

func GetSum(num1, num2 int, handleFunc AddHandleFunc) int {
    return handleFunc(num1, num2)
}

基于函數 func(num1, num2 int) int 自定義一個類型 AddHandleFunc,將它聲明為 GetSum 的形參,然后調用 GetSum 時,因為 Add 函數和 AddHandleFunc 是等價的,因此可以將 Add 當做實參傳進去。

小結

本文對函數的聲明進行介紹,根據一個案例了解了其組成的5部分。然后介紹了其一些特點如支持變長參數、傳遞參數時,實參按值傳遞等,最后根據函數在Go中是一種數據類型的特點,說明了其一些特別用法。

原文鏈接:https://juejin.cn/post/7171068063021400100

欄目分類
最近更新