原文:CalliCoder — Introduction to Functions in Golang
函數是一個程式碼區塊,它接受一些輸入,對該輸入進行一些處理,並產生一些輸出。
函數可以協助你將程式劃分為可重複使用的小段程式碼。它們提高了程式的可讀性、可維護性和可測試性。
在 Golang 宣告和呼叫函數
在 Golang 中,我們使用 func
關鍵字宣告函數。函數具有一個名稱、以逗號分隔的輸入參數及其型別的列表、結果型別和主體。
以下是一個簡單函數 avg
的範例,該函數接受兩個型別為 float64
的輸入參數,並返回輸入的平均值。結果也是 float64
型別:
func avg(x float64, y float64) float64 {
return (x + y) / 2
}
現在,呼叫函數非常簡單。你只需要像這樣將所需數量的參數傳遞給函數:
avg(6.56, 13.44)
這是一個完整範例:
package main
import "fmt"
func avg(x float64, y float64) float64 {
return (x + y) / 2
}
func main() {
x := 5.75
y := 6.25
result := avg(x, y)
fmt.Printf("Average of %.2f and %.2f = %.2f\n", x, y, result)
}
# Output
Average of 5.75 and 6.25 = 6.00
函數參數和返回型別是非必要的
輸入參數和返回型別對於函數是非必要的。可以宣告一個沒有任何輸入和輸出的函數。
main()
函數是此類函數的範例:
func main() {
}
這是另一個範例:
func sayHello() {
fmt.Println("Hello, World")
}
你只需要為同一型別的多個連續參數指定一次型別
如果一個函數具有兩個或更多個相同型別的連續參數,那麼只需為該型別的最後一個參數指定一次即可。
舉例來說,我們也可以像這樣宣告我們在上一節中看到的 avg
函數:
func avg(x, y float64) float64 { }
// Same as - func avg(x float64, y float64) float64 { }
這是另一個範例:
func printPersonDetails(firstName, lastName string, age int) { }
// Same as - func printPersonDetails(firstName string, lastName string, age int) { }
具有多個返回值的函數
Go 函數能夠返回多個值。沒錯!大多數程式語言都不支援此功能。但 Go 是不同的。
假設你要建立一個函數,該函數接受股票的_先前價格_和_目前價格_,並返回價格變動的金額和百分比。
以下是你如何在 Go 實作這種函數的方法:
func getStockPriceChange(prevPrice, currentPrice float64) (float64, float64) {
change := currentPrice - prevPrice
percentChange := (change / prevPrice) * 100
return change, percentChange
}
很間單,對吧?你只需要在括號內用逗號分隔指定的返回型別,然後從函數中返回多個逗號分隔的值即可。
讓我們來看一個具有 main()
函數的完整範例:
package main
import (
"fmt"
"math"
)
func getStockPriceChange(prevPrice, currentPrice float64) (float64, float64) {
change := currentPrice - prevPrice
percentChange := (change / prevPrice) * 100
return change, percentChange
}
func main() {
prevStockPrice := 75000.0
currentStockPrice := 100000.0
change, percentChange := getStockPriceChange(prevStockPrice, currentStockPrice)
if change < 0 {
fmt.Printf("The Stock Price decreased by $%.2f which is %.2f%% of the prev price\n", math.Abs(change), math.Abs(percentChange))
} else {
fmt.Printf("The Stock Price increased by $%.2f which is %.2f%% of the prev price\n", change, percentChange)
}
}
# Output
The Stock Price increased by $25000.00 which is 33.33% of the prev price
從函數返回錯誤值
Golang 中經常使用多個返回值來從函數返回錯誤與結果。
我們來看一個範例:如果 prevPrice
是 0
,則在上一節看到的 getStockPriceChange
函數將返回 ±Inf
(無限大)。如果你想返回錯誤,則可以透過增加一個型別為 error
的返回值,並像這樣返回錯誤值:
func getStockPriceChangeWithError(prevPrice, currentPrice float64) (float64, float64, error) {
if prevPrice == 0 {
err := errors.New("Previous price cannot be zero")
return 0, 0, err
}
change := currentPrice - prevPrice
percentChange := (change / prevPrice) * 100
return change, percentChange, nil
}
error
型別是 Golang 中內建的型別。Go 程式使用 error
值來顯示異常情況。如果你現在不了解 error
請別擔心。你將在以後的文章中了解更多有關錯誤處理的資訊。
以下是使用 main()
函數示範上述觀念的完整範例:
package main
import (
"errors"
"fmt"
"math"
)
func getStockPriceChangeWithError(prevPrice, currentPrice float64) (float64, float64, error) {
if prevPrice == 0 {
err := errors.New("Previous price cannot be zero")
return 0, 0, err
}
change := currentPrice - prevPrice
percentChange := (change / prevPrice) * 100
return change, percentChange, nil
}
func main() {
prevStockPrice := 0.0
currentStockPrice := 100000.0
change, percentChange, err := getStockPriceChangeWithError(prevStockPrice, currentStockPrice)
if err != nil {
fmt.Println("Sorry! There was an error: ", err)
} else {
if change < 0 {
fmt.Printf("The Stock Price decreased by $%.2f which is %.2f%% of the prev price\n", math.Abs(change), math.Abs(percentChange))
} else {
fmt.Printf("The Stock Price increased by $%.2f which is %.2f%% of the prev price\n", change, percentChange)
}
}
}
# Output
Sorry! There was an error: Previous price cannot be zero
具有命名返回值的函數
在 Golang 中,函數的返回值可以被命名。命名返回值的行為就像你在函數頂部定義它們一樣。
讓我們用命名的返回值重寫在上一節看到的 getStockPriceChange
函數:
// Function with named return values
func getNamedStockPriceChange(prevPrice, currentPrice float64) (change, percentChange float64) {
change = currentPrice - prevPrice
percentChange = (change / prevPrice) * 100
return change, percentChange
}
注意我們如何在函數主體中將 :=
(簡短宣告)更改為 =
(賦值)。這是因為 Go 本身定義了所有命名的返回值,並讓它們可以在函數中使用。由於它們已經定義,因此你無法使用簡短宣告再次定義它們。
命名返回值允許你使用所謂的裸返回(不帶任何參數的 return
陳述式)。當你指定一個不帶任何參數的 return
陳述式時,預設情況下它會返回命名的返回值。因此,你也可以像這樣撰寫以上功能:
// Function with named return values and naked return
func getNamedStockPriceChange(prevPrice, currentPrice float64) (change, percentChange float64) {
change = currentPrice - prevPrice
percentChange = (change / prevPrice) * 100
return
}
讓我們在帶有 main()
函數的完整範例中使用上述函數,並驗證輸出:
package main
import (
"fmt"
"math"
)
func getNamedStockPriceChange(prevPrice, currentPrice float64) (change, percentChange float64) {
change = currentPrice - prevPrice
percentChange = (change / prevPrice) * 100
return
}
func main() {
prevStockPrice := 100000.0
currentStockPrice := 90000.0
change, percentChange := getNamedStockPriceChange(prevStockPrice, currentStockPrice)
if change < 0 {
fmt.Printf("The Stock Price decreased by $%.2f which is %.2f%% of the prev price\n", math.Abs(change), math.Abs(percentChange))
} else {
fmt.Printf("The Stock Price increased by $%.2f which is %.2f%% of the prev price\n", change, percentChange)
}
}
# Output
The Stock Price decreased by $10000.00 which is 10.00% of the prev price
命名返回值提高了函數的可讀性。使用有意義的名稱可讓函數的使用者僅透過查看其簽名即可知道函數將返回什麼。
裸返回陳述式適合較短的函數。但如果你的函數比較長,請不要使用它們。它們可能會損害可讀性。你應該在更長的函數中明確地指定返回值。
空白識別符號
有時候你可能想忽略返回多個值的函數的某些結果。
舉例來說,假設你在使用我們上一節定義的 getStockPriceChange
函數,但你只對價格變動感興趣,而不是變動百分比。
現在,你可以像這樣宣告區域變數並儲存從函數返回的所有值:
change, percentChange := getStockPriceChange(prevStockPrice, currentStockPrice)
但是在那種情況下,你將被迫使用 percentChange
變數,因為 Go 不允許建立你從未使用過的變數。
那有什麼解決方案?嗯,你可以改用_空白識別符號_:
change, _ := getStockPriceChange(prevStockPrice, currentStockPrice)
空白識別符號用來告訴 Go 你不需要這個值。以下範例示範了此觀念:
package main
import (
"fmt"
"math"
)
func getStockPriceChange(prevPrice, currentPrice float64) (float64, float64) {
change := currentPrice - prevPrice
percentChange := (change / prevPrice) * 100
return change, percentChange
}
func main() {
prevStockPrice := 80000.0
currentStockPrice := 120000.0
change, _ := getStockPriceChange(prevStockPrice, currentStockPrice)
if change < 0 {
fmt.Printf("The Stock Price decreased by $%.2f\n", math.Abs(change))
} else {
fmt.Printf("The Stock Price increased by $%.2f\n", change)
}
}
# Output
The Stock Price increased by $40000.00
結論
在本文中,你學到了如何在 Golang 中定義和呼叫函數、如何定義具有多個返回值和命名返回值的函數、如何從函數返回錯誤,以及如何使用空白識別符號。