函式

函式 在 Go

1 個練習

關於 函式

函式讓你能把程式碼組成一個可重複使用的單位。 它由func關鍵字、函式名稱,以及放在括號中、以逗號分隔的 0 個或多個參數與型別組成。

函式參數

所有參數都必須明確標註型別;參數沒有型別推斷。 參數沒有預設值,因此所有函式參數都是必填的。

import "fmt"

// No parameters
func PrintHello() {
    fmt.Println("Hello")
}

// One parameter
func PrintHelloName(name string) {
  fmt.Println("Hello " + name)
}

相同型別的參數可以一起宣告,後面接一個型別宣告。

import "fmt"

func PrintGreetingName(greeting, name string) {
  fmt.Println(greeting + " " + name)
}

參數與引數

我們快速看一下兩個經常被混淆的詞:parameters和arguments。 函式參數是定義在函式簽章裡的名稱,例如上面PrintGreetingName函式中的greeting和name。 函式引數則是我們呼叫函式時,實際傳給函式參數的具體值。 例如在下面的範例中,"Hello"和"Katrina"就是傳給greeting和name參數的引數:

PrintGreetingName("Hello", "Katrina")

回傳值

函式參數之後是 0 個或多個回傳值,這些回傳值也必須明確標註型別。 只有一個回傳值時直接寫出,多個回傳值則用括號包起來。 函式使用 return 關鍵字把值回傳給呼叫的程式碼。 一個函式裡可以有多個return敘述。 一旦執行到其中一個return敘述,函式的執行就會結束。 如果要從函式回傳多個值,它們以逗號分隔。 關於多個回傳值的慣用寫法,可以在連結的概念頁面中找到更多資訊。

func Hello(name string) string {
  return "Hello " + name
}

func HelloAndGoodbye(name string) (string, string) {
  return "Hello " + name, "Goodbye " + name
}

呼叫函式

呼叫函式時,要指定函式名稱,並在括號中為函式的每個參數傳入引數。

import "fmt"

// No parameters, no return value
func PrintHello() {
    fmt.Println("Hello")
}
// Called like this:
PrintHello()

// One parameter, one return value
func Hello(name string) string {
  return "Hello " + name
}
// Called like this:
greeting := Hello("Dave")

// Multiple parameters, multiple return values
func SumAndMultiply(a, b int) (int, int) {
    return a+b, a*b
}
// Called like this:
aplusb, atimesb := SumAndMultiply(a, b)

具名回傳值與裸回傳

除了參數之外,回傳值也可以選擇性地命名。 如果使用了具名回傳值,不帶引數的return敘述就會回傳這些值。 這就是所謂的「裸」回傳。

func SumAndMultiplyThenMinus(a, b, c int) (sum, mult int) {
    sum, mult = a+b, a*b
    sum -= c
    mult -= c
    return
}

傳值與傳參考

釐清傳值和傳參考的概念也很重要。

首先,我們來釐清傳值。 在下面的範例中,當我們把變數val傳給MultiplyByTwo函式時,傳入的是val的副本。 因此,newVal的值更新為4,但原始的變數val仍然是2。 實際上,Go 本質上會複製原始值,所以只有這個副本(也就是v)會被函式修改。

val := 2
func MultiplyByTwo(v int) int {
    v = v * 2
    return v
}
newVal := MultiplyByTwo(val)
// newval is 4, val is still 2 because only a copy of its value was passed into the function

嚴格來說,在 Go 中所有引數都是傳值,也就是說,會複製提供給函式的值或資料。 但如果你不想複製傳入函式的資料,而想在函式中修改資料,就應該使用pointers作為引數,也就是傳參考。

指標

我們使用pointer來達成傳參考。 把pointer引數傳入函式,就能修改傳入函式的底層資料,而不只是對資料的副本操作。

目前只要知道,指標型別可以從函式簽章中型別前面的*認出來就夠了。

func HandlePointers(x, y *int) {
    // Some logic to handle integer values referenced by pointers x and y
}

如果pointer的概念讓你感到困惑,別擔心。 課程大綱後面有一個專門的章節,可以幫助你精通指標。

例外情況

請注意,slices和maps是上述規則的例外。 當我們把slice或map作為引數傳入函式時,即使型別中沒有明確的*,它們也會被當成指標型別處理。 這表示如果我們把 slice 或 map 傳入函式並修改其底層資料,這些變更會反映到原始的 slice 或 map 上。

其他型別的函式

在 Go 中,函式被視為一級公民,這讓它們非常強大。 圍繞函式還有許多其他概念,例如方法和匿名函式,你會在之後的學習旅程中遇到。

透過 GitHub 編輯 連結會在新視窗或分頁中開啟

學習 函式