iT邦幫忙

2022 iThome 鐵人賽

DAY 25
0
自我挑戰組

跟著 Go 實戰聖經 一起自學 Go系列 第 25

DAY 25 Go 語言 函式 (function) 傳回值

  • 分享至 

  • xImage
  •  

函式傳回值

前面我們練習的函式都沒有傳回值,但是正常函式會有輸入值,然後再執行函式完成後,會有傳回值,特別的是 Go 語言中的傳回值可以是 0 ~ 多個 (一直在洗腦)

值 1, 值 2... := 函式名稱()

補充:
有傳回值的函式裡面要有 return 敘述,若是遺漏他,一樣是會報錯的。

以下範例我們根據書中自己定義的 fizzBuzz() 函式作為基底,並傳回走訪到的數字以及對應到的字串。
fizzBuzz() 函式的規則:

  1. 用迴圈將數字從 1 累加到某值,並印出該值
  2. 若為 3 的倍數,顯示文字「Fizz」。
  3. 若為 5 的倍數,顯示文字「Buzz」。
  4. 若為 3 和 5 的公倍數 (15的倍數),顯示文字「FixxBuzz」。

範例 1:

package main

import "fmt"

func main() {
    for i := 1; i <= 15; i++ {
        n, s := fizzBuzz(i)
        fmt.Println("數字:", n, "對應字串:",  s)
    } 
}

func fizzBuzz(i int) (int, string) {
    switch {
    case i % 15 == 0:
        return i, "FizzBuzz"
    case i % 5 == 0:
        return i, "Buzz"
    case i % 3 == 0:
        return i, "Fizz"
    }
    return i, ""
}

範例 1(執行結果):

數字: 1 對應字串: 
數字: 2 對應字串: 
數字: 3 對應字串: Fizz
數字: 4 對應字串: 
數字: 5 對應字串: Buzz
數字: 6 對應字串: Fizz
數字: 7 對應字串: 
數字: 8 對應字串: 
數字: 9 對應字串: Fizz
數字: 10 對應字串: Buzz
數字: 11 對應字串: 
數字: 12 對應字串: Fizz
數字: 13 對應字串: 
數字: 14 對應字串: 
數字: 15 對應字串: FizzBuzz

忽略部分傳回值

有時候我們在很多地方重複呼叫一個函式,但或許每個地方需要的傳回值,並不一定跟本來函式的傳回值數量相同,這時可以便可以使用 底線 _ 來忽略傳回值。
以範例 1 作為例子,若我這時不需要印出前一個回傳值 (數字) ,那就可以寫成如範例二的寫法:
範例 2:

package main

import "fmt"

func main() {
    for i := 1; i <= 15; i++ {
        _, s := fizzBuzz(i) // 以底線 _ 來忽略回傳值
        fmt.Println("對應字串:",  s)
    } 
}

func fizzBuzz(i int) (int, string) {
    switch {
    case i % 15 == 0:
        return i, "FizzBuzz"
    case i % 5 == 0:
        return i, "Buzz"
    case i % 3 == 0:
        return i, "Fizz"
    }
    return i, ""
}

範例 2(執行結果):

對應字串: 
對應字串: 
對應字串: Fizz
對應字串: 
對應字串: Buzz
對應字串: Fizz
對應字串: 
對應字串: 
對應字串: Fizz
對應字串: Buzz
對應字串: 
對應字串: Fizz
對應字串: 
對應字串: 
對應字串: FizzBuzz

補充:
若是如範例 2 相同使用短變數宣告賦值時, := 的左邊至少需要有一個實際的變數,若是上面兩個傳回值都用 _ 接收, Go 語言便會報以下錯誤訊息。

no new variables on left side of :=

又或者是有時需要讀取檔案時,檔案會傳回我們讀取的位元組數量以及淺在錯誤,但我們只需要知道讀取的檔案是否存在(查無檔案會傳入 error),不需要知道有多少位元組數,這時也可以把傳回的第一個參數用 _ 省略,如下:

_, err := file.Read(bytes)

補充:
在 Go 語言的函式慣例會以 error 作為第二個傳回值。
且對於可能傳回 error 的函式,應該要妥善處理 (做好錯誤處理) ,才可以避免意料外的後果發生。

結構方法

在鐵人賽 Day 21 時,我們有介紹結構方法,雖然呼叫結構方法跟呼叫函式有些許不同,但其實結構方法也是函式的一種,所以參數以及傳回值的寫法都是用於我們前面函式介紹到的寫法呦~

Naked Returns

在宣告 Go 語言函式時,我們若給傳回值加上變數名稱,就會在函式內建立該名稱的區域變數,作用範圍一樣存在於函式內,如此一來我們便可以在函式內對於變數賦值。
範例 3:

package main

import "fmt"

func printMyFavorite() (name string, age int) {
    name = "奇犽" // name 變數已經在傳回值建立,故這邊直接使用 = 賦值
    age = 12
    return name, age
}

func main(){
    fmt.Println(printMyFavorite())  // 印出執行 printMyFavorite() 的結果,也就是 return 的 name 跟 age
}

範例 3(執行結果):

奇犽 12

如果沒有在 return 敘述後面指定要傳回的變數, Go 語言便會自己將傳回值清單的變數傳回,這就是 naked returns ,也可以稱為 具名 return (named return)

範例 4:

package main

import "fmt"

func printMyFavorite() (name string, age int) {
    name = "奇犽" // name 變數已經在傳回值建立,故這邊直接使用 = 賦值
    age = 12
    return // 沒有在 return 敘述後面指定要傳回的變數, 會自己將傳回值name, age
}

func main(){
    fmt.Println(printMyFavorite())  // 印出執行 printMyFavorite() 的結果,也就是 return 的 name 跟 age
}

範例 4(執行結果):

奇犽 12

但若是再稍微長一些或是複雜一些的函式中,就不建議使用 naked returns ,因為會變得不好閱讀,以及讓人搞混傳回值。另外還有可能發生 變數遮蔽 (shadowing) 的問題。

範例 5:

package main

import "fmt"

func message() (message string, err error) {
    message = "錯誤" 
    if message == "錯誤"{
        err := fmt.Errorf("這是錯誤的訊息呦!")
        return
    }
    return // 沒有在 return 敘述後面指定要傳回的變數, 會自己將傳回值name, age
}

func main(){
    fmt.Println(message())
}

範例 5(執行結果):

./main.go:1092:9: err declared but not used
./main.go:1093:9: result parameter err not in scope at return
./main.go:1092:9: inner declaration of var err error

這是因為我們在傳回值已經宣告了 err 變數,但是在 if 敘述中又重新宣告和初始化 err 變數,會造成 變數遮蔽 (shadowing) 讓 Go 程式不知道現在到底是要 return 哪一個 err ,要修改只要明確寫上 return 敘述即可。

package main

import "fmt"

func message() (message string, err error) {
    message = "錯誤" 
    if message == "錯誤"{
        err := fmt.Errorf("這是錯誤的訊息呦!")
        return message, err
    }
    return // 沒有在 return 敘述後面指定要傳回的變數, 會自己將傳回值name, age
}

func main(){
    fmt.Println(message())
}
錯誤 這是錯誤的訊息呦!

今天介紹在 Go 語言中函式 (function) 的傳回值,那我們明天繼續學習參數不定的函式,明天見~~


上一篇
DAY 24 Go 語言 函式 (function) 呼叫及參數
下一篇
DAY 26 Go 語言 函式 (function) 參數不定函式
系列文
跟著 Go 實戰聖經 一起自學 Go30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言