🚀 Golang 函數:從入門到精通

更新於 發佈於 閱讀時間約 20 分鐘


raw-image

👨‍💻簡介

在 Go 語言中,函數(Function)是一個強大且重要的概念,就像食譜一樣,告訴你應該如何處理食材,最後得到一道美味的料理。經過哪些程序讓程式更有組織性和可讀性。函數可幫助你將程式碼區塊組織成可重複使用的元件,進而執行特定的任務。本文要帶你一探究竟,深入了解 Golang 裡的函數有哪些不同的方面。從基本的概念開始,一路講到更高級的技巧,我們會告訴你怎麼樣用函數來處理各種不同的情況。

函數基本概念

函數在 Golang 中是一組程式語句的組合,用於執行特定的任務。它們接受輸入(參數)並返回輸出(返回值),從高層次來看,就像是黑盒子,你提供輸入,它交付結果。在每個 Golang 程式中,最常見的函數是 main(),它是程式的入口點。

函數名稱與命名規則

在 Golang 中,函數名稱的命名規則如下:

  • 名稱必須以字母開始,後面可以是任意數量的字母和數字。
  • 函數名稱不能以數字開頭。
  • 函數名稱不能包含空格。
  • 如果函數名稱以大寫字母開頭,則可以被其他套件引用。如果以小寫字母開頭,則不能被其他套件引用,但可以在同一套件內部使用。
  • 如果名稱由多個單詞組成,從第二個單詞開始的每個單詞首字母應大寫,例如 empNameEmpAddress 等。
  • 函數名稱區分大小寫,即 carCar 和 CAR 是三個不同的變數。

創建函數

在 Golang 中,創建函數的基本語法如下:

func 函數名稱(參數1 型別1, 參數2 型別2, ...) 返回型別 {
// 函數程式碼
return 返回值
}

首先,用 func 關鍵字開始函數宣告,然後是你想要給函數的名稱,一對括號 (),然後是一個包含函數程式碼的區塊。

以下是一個簡單的範例,它不接受任何參數,也不返回任何值。

package main

import "fmt"
// SimpleFunction 印出一個訊息
func SimpleFunction() {
fmt.Println("Hello World")
}
func main() {
SimpleFunction() // 呼叫 SimpleFunction 函數
}

接受參數的函數

如果要將資訊傳遞給函數,可以通過參數來實現。參數就像變數一樣。

在函數名稱後面的括號內指定參數。你可以添加任意多的參數,只需用逗號分隔。

以下是一個帶有兩個整數參數的範例。當呼叫 add() 函數時,我們傳遞了兩個整數值(例如 20 和 30)。

package main

import "fmt"
// 接受參數的函數
func add(x int, y int) {
total := 0
total = x + y
fmt.Println(total)
}
func main() {
// 傳遞參數
add(20, 30)
}

在 Golang 中,函數名稱首字母大寫的話,可以被其他套件引用(export)使用。如果函數名稱首字母小寫,則不能被其他套件引用,但在同一套件內部可以呼叫該函數。

返回值的函數

如果要在函數中返回值,可以在函數中指定返回類型。以下是一個計算兩個整數之和並返回結果的範例:

package main

import "fmt"
// 函數返回 int 型別的值
func add(x int, y int) int {
total := x + y
return total
}
func main() {
// 接收返回值並存入變數
sum := add(20, 30)
fmt.Println(sum)
}

命名返回值的函數

在 Golang 中,函數的返回值可以命名。這意味著你可以在函數中指定返回值的名稱,並在函數內部直接使用這些名稱。

以下是一個計算矩形面積和周長的範例:

package main

import "fmt"
func rectangle(l int, b int) (area int) {
parameter := 2 * (l + b)
fmt.Println("周長:", parameter)
area = l * b
return// 省略返回值變數,使用命名的返回
}
func main() {
fmt.Println("面積:", rectangle(20, 30))
}

返回多個值的函數

函數還可以返回多個值,這在處理多個相關的值時非常方便。以下是一個返回矩形面積和周長的範例:

package main

import "fmt"
// rectangle 是一個計算矩形面積和周長的函數,返回兩個值
func rectangle(length int, breadth int) (area int, perimeter int) {
perimeter = 2 * (length + breadth)
area = length * breadth
return // 省略返回值變數,使用命名的返回
}
func main() {
a, p := rectangle(10, 5) // 呼叫 rectangle 函數並接收返回值
fmt.Println("面積:", a)
fmt.Println("周長:", p)
}

將位址傳遞給函數進行值更新

在 Golang 中,你還可以將變數的位址傳遞給函數,並且在函數內部透過解引用的方式來修改變數的值。以下範例將展示這種通過位址更新變數值的情境:

package main

import "fmt"
func update(a *int, t *string) {
*a = *a + 5 // 透過解引用位址修改變數值
*t = *t + " Doe" // 透過解引用位址修改變數值
return
}
func main() {
var age = 20
var text = "John"
fmt.Println("修改前:", text, age)
update(&age, &text)
fmt.Println("修改後:", text, age)
}

匿名函數:更靈活的處理

在 Golang 中,還可以使用匿名函數。匿名函數是一種無需命名識別符即可宣告的函數。匿名函數可以接受輸入並返回輸出,就像普通函數一樣。以下是一個將函數指派給變數並使用匿名函數:

package main

import "fmt"
var (
area = func(l int, b int) int {
return l * b
}
)
func main() {
fmt.Println(area(20, 30))
}

你還可以將參數傳遞給匿名函數:

package main

import "fmt"
func main() {
func(l int, b int) {
fmt.Println(l * b)
}(20, 30)
}

匿名函數也可以接受參數並返回值:

package main

import "fmt"
func main() {
fmt.Printf(
"100 (°F) = %.2f (°C)\n",
func(f float64) float64 {
return (f - 32.0) * (5.0 / 9.0)
}(100),
)
}

閉包:捕獲外部變數

在 Golang 中,閉包是匿名函數的一種特殊情形。閉包是可以存取在函數外部定義的變數的匿名函數。

以下是一個使用閉包的範例,其中匿名函數可以訪問在函數外部定義的變數:

package main

import "fmt"
func main() {
l := 20
b := 30
func() {
var area int
area = l * b
fmt.Println(area)
}()
}

另一個範例是,在函數內的迴圈迭代過程中,匿名函數可以訪問變數的值:

package main

import "fmt"
func main() {
for i := 10.0; i < 100; i += 10.0 {
rad := func() float64 {
return i * 39.370
}()
fmt.Printf("%.2f 公尺 = %.2f 英吋\n", i, rad)
}
}

高階函數:函數作為參數和返回值

在 Golang 中,函數可以作為參數傳遞給其他函數,也可以作為函數的返回值。這種功能稱為高階函數(Higher-Order Functions),能夠提供更靈活且模組化的程式設計方式。以下範例演示如何創建一個高階函數,將一個函數套用到切片的每個元素:

package main

import (
"fmt"
"strings"
)
// mapString 將 f 函數套用到每個字串元素並返回新的切片
func mapString(arr []string, f func(string) string) []string {
result := make([]string, len(arr))
for i, v := range arr {
result[i] = f(v)
}
return result
}
func main() {
words := []string{"apple", "banana", "cherry"}
toUpper := func(s string) string {
return strings.ToUpper(s)
}
upperWords := mapString(words, toUpper)
fmt.Println(upperWords) // 輸出:[APPLE BANANA CHERRY]
}

函數作為參數傳遞給其他函數

以下是一個將函數作為參數傳遞給高階函數的範例:

package main

import "fmt"
func sum(x, y int) int {
return x + y
}
func partialSum(x int) func(int) int {
return func(y int) int {
return sum(x, y)
}
}
func main() {
partial := partialSum(3)
fmt.Println(partial(7))
}

將函數作為結果返回的高階函數

你還可以將函數作為結果返回,這被稱為返回函數的高階函數。以下是一個範例,該範例返回一個函數,該函數在其內部使用嵌套的匿名函數:

package main

import "fmt"
func squareSum(x int) func(int) func(int) int {
return func(y int) func(int) int {
return func(z int) int {
return x*x + y*y + z*z
}
}
}
func main() {
resultFunc := squareSum(5) // 返回一個函數
subResultFunc := resultFunc(6) // 返回一個嵌套函數
finalResult := subResultFunc(7) // 呼叫最內層的函數獲取結果
fmt.Println(finalResult) // 印出最終計算結果
fmt.Println(squareSum(5)(6)(7))
}

自定義函數類型

在 Golang 中,你可以使用 type 關鍵字定義自己的函數類型。這就像是為函數創建了一個別名,使得該函數類型能夠被用作變數的型別。自定義函數類型能夠讓你更好地組織程式碼,以及在特定情境下使代碼更具表達性。

以下是一個使用自定義函數類型的範例,我們將創建一個函數類型 First,並進一步使用 Second 函數類型。這些自定義的函數類型可以用於創建一個執行特定計算的函數:

package main

import "fmt"
// 定義 First 函數類型
type First func(int) int
// 定義 Second 函數類型
type Second func(int) First
// squareSum 返回一個 Second 函數
func squareSum(x int) Second {
return func(y int) First {
return func(z int) int {
return x*x + y*y + z*z
}
}
}
func main() {
// 使用自定義函數類型的範例
result := squareSum(5)(6)(7)
fmt.Println("計算結果:", result) // 輸出:110
}

函數的特性、限制與使用場景

函數是程式設計中的重要組成部分,它們能夠將程式碼模組化、重複使用,使程式更具可讀性和可維護性。然而,函數也有其特性、限制以及適用的使用場景,讓我們來一起深入了解。

函數的特性

  1. 模組化: 函數能夠將程式碼分成小的模組,使得程式邏輯更加清晰,也更容易進行測試和修改。
  2. 重複使用: 定義一次函數後,你可以在程式中多次調用它,避免了重複編寫相同的程式碼。
  3. 參數和返回值: 函數可以接受參數,這些參數提供了執行函數所需的資訊。同時,函數可以返回值,使得結果能夠被其他程式碼使用。
  4. 封裝: 函數能夠封裝實現細節,隱藏程式碼的複雜性,使得外部使用者只需關心函數的功能。
  5. 遞迴: 函數可以呼叫自己,這種稱為遞迴的特性在處理某些問題時非常有用。

函數的限制

  1. 可讀性: 過多的函數調用可能導致程式難以閱讀和理解,因此需要適當的拆分和命名函數。
  2. 效能考慮: 過於頻繁的函數調用可能會影響程式的效能,因為每次函數呼叫都會有一定的開銷。
  3. 記憶體使用: 函數的呼叫需要保留堆疊帧等相關資訊,這可能會佔用一些記憶體空間。
  4. 可變性: 在某些程式語言中,函數可能會更改其外部範疇的變數,這可能導致程式難以理解和調試。

函數的使用場景

  1. 程式模組化: 將相關的程式碼封裝為函數,可以使程式更具結構,更容易維護。
  2. 代碼重用: 如果你在多個地方需要執行相同或類似的操作,可以將這些操作封裝成函數,方便重複使用。
  3. 抽象化: 函數可以將複雜的實現細節隱藏起來,只暴露必要的介面,使外部程式碼更易於理解。
  4. 遞迴問題: 某些問題的解決方案適合使用遞迴,例如數學中的遞迴定義和分治算法。
  5. 事件處理: 在事件驅動的程式中,函數可以用於處理不同的事件類型,使程式具有彈性。
  6. 資料轉換: 函數可以用於將一種資料類型轉換為另一種,例如日期格式轉換、單位轉換等。
  7. 處理業務邏輯: 在軟體應用中,函數可以用於實現業務邏輯,如處理訂單、用戶驗證等。
  8. 演算法實現: 函數是實現演算法的基本元素,能夠將複雜的演算法分解成可管理的部分。

函數的常見用法

1. 計算數值的平方和

package main

import "fmt"
func squareSum(numbers ...int) int {
sum := 0
for _, num := range numbers {
sum += num * num
}
return sum
}
func main() {
result := squareSum(2, 3, 4)
fmt.Println("平方和:", result)
}

2. 找出切片中的最大值

package main

import (
"fmt"
"math"
)
func findMax(numbers ...float64) float64 {
max := math.Inf(-1)
for _, num := range numbers {
if num > max {
max = num
}
}
return max
}
func main() {
result := findMax(2.3, 5.7, 1.2, 9.8)
fmt.Println("最大值:", result)
}

3. 檢查字串是否為回文

package main

import (
"fmt"
"strings"
)
func isPalindrome(s string) bool {
s = strings.ToLower(s)
for i := 0; i < len(s)/2; i++ {
if s[i] != s[len(s)-1-i] {
return false
}
}
return true
}
func main() {
result := isPalindrome("racecar")
fmt.Println("是否為回文:", result)
}

4. 計算 Fibonacci 數列

package main

import "fmt"
func fibonacci(n int) int {
if n <= 0 {
return 0
} else if n == 1 {
return 1
}
return fibonacci(n-1) + fibonacci(n-2)
}
func main() {
result := fibonacci(6)
fmt.Println("第 6 個 Fibonacci 數:", result)
}

5. 判斷是否為質數

package main

import "fmt"
func isPrime(n int) bool {
if n <= 1 {
return false
}
for i := 2; i*i <= n; i++ {
if n%i == 0 {
return false
}
}
return true
}
func main() {
result := isPrime(17)
fmt.Println("17 是否為質數:", result)
}

小結

函數是 Golang 程式設計的基石之一,讓你能夠組織程式碼、提高重用性,並以更模組化的方式處理不同情境的需求。無論是創建簡單的函數、使用閉包捕獲變數,還是運用高階函數進行模組化設計,函數都在 Golang 中扮演著關鍵角色。

📚Reference

留言
avatar-img
留言分享你的想法!
avatar-img
Alan的開發者天地
19會員
83內容數
golang
Alan的開發者天地的其他內容
2023/10/04
👨‍💻 簡介 最近想要透過小實作來撰寫筆記,達到做中學的效果,因此就來實作個小爬蟲順便結合前面學到的package做一個小複習。
Thumbnail
2023/10/04
👨‍💻 簡介 最近想要透過小實作來撰寫筆記,達到做中學的效果,因此就來實作個小爬蟲順便結合前面學到的package做一個小複習。
Thumbnail
2023/09/28
👨‍💻簡介 今天來介紹一個自己開發後端蠻常用的一個 package,promptui,拿來做menu真的很方便,promptui有兩個主要的輸入模式: Prompt:跳出單行使用者輸入。 Select:提供一個選項列表供使用者選擇。
Thumbnail
2023/09/28
👨‍💻簡介 今天來介紹一個自己開發後端蠻常用的一個 package,promptui,拿來做menu真的很方便,promptui有兩個主要的輸入模式: Prompt:跳出單行使用者輸入。 Select:提供一個選項列表供使用者選擇。
Thumbnail
2023/09/26
👨‍💻 簡介 在處理string時,正則表達式是一個非常有用的工具。Go語言的regexp package 可以使用正則表達式,用來執行如檢查string是否匹配某個模式、提取匹配的subString等操作。
Thumbnail
2023/09/26
👨‍💻 簡介 在處理string時,正則表達式是一個非常有用的工具。Go語言的regexp package 可以使用正則表達式,用來執行如檢查string是否匹配某個模式、提取匹配的subString等操作。
Thumbnail
看更多
你可能也想看
Thumbnail
透過蝦皮分潤計畫,輕鬆賺取零用金!本文分享5-6月實測心得,包含數據流程、實際收入、平臺優點及注意事項,並推薦高分潤商品,教你如何運用空閒時間創造被動收入。
Thumbnail
透過蝦皮分潤計畫,輕鬆賺取零用金!本文分享5-6月實測心得,包含數據流程、實際收入、平臺優點及注意事項,並推薦高分潤商品,教你如何運用空閒時間創造被動收入。
Thumbnail
單身的人有些會養寵物,而我養植物。畢竟寵物離世會傷心,植物沒養好再接再厲就好了~(笑)
Thumbnail
單身的人有些會養寵物,而我養植物。畢竟寵物離世會傷心,植物沒養好再接再厲就好了~(笑)
Thumbnail
不知你有沒有過這種經驗?衛生紙只剩最後一包、洗衣精倒不出來,或電池突然沒電。這次一次補貨,從電池、衛生紙到洗衣精,還順便分享使用心得。更棒的是,搭配蝦皮分潤計畫,愛用品不僅自己用得安心,分享給朋友還能賺回饋。立即使用推薦碼 X5Q344E,輕鬆上手,隨時隨地賺取分潤!
Thumbnail
不知你有沒有過這種經驗?衛生紙只剩最後一包、洗衣精倒不出來,或電池突然沒電。這次一次補貨,從電池、衛生紙到洗衣精,還順便分享使用心得。更棒的是,搭配蝦皮分潤計畫,愛用品不僅自己用得安心,分享給朋友還能賺回饋。立即使用推薦碼 X5Q344E,輕鬆上手,隨時隨地賺取分潤!
Thumbnail
身為一個典型的社畜,上班時間被會議、進度、KPI 塞得滿滿,下班後只想要找一個能夠安靜喘口氣的小角落。對我來說,畫畫就是那個屬於自己的小樹洞。無論是胡亂塗鴉,還是慢慢描繪喜歡的插畫人物,那個專注在筆觸和色彩的過程,就像在幫心靈按摩一樣,讓緊繃的神經慢慢鬆開。
Thumbnail
身為一個典型的社畜,上班時間被會議、進度、KPI 塞得滿滿,下班後只想要找一個能夠安靜喘口氣的小角落。對我來說,畫畫就是那個屬於自己的小樹洞。無論是胡亂塗鴉,還是慢慢描繪喜歡的插畫人物,那個專注在筆觸和色彩的過程,就像在幫心靈按摩一樣,讓緊繃的神經慢慢鬆開。
Thumbnail
本章節旨在介紹 C# 中函數的基本結構,包括訪問修飾符、返回類型、方法名稱、參數列表和方法體。同時,也介紹了函數的各種呼叫方式、參數傳遞方式和返回值類型。讀者可以通過本章節,深入理解 C# 中函數的使用和應用。
Thumbnail
本章節旨在介紹 C# 中函數的基本結構,包括訪問修飾符、返回類型、方法名稱、參數列表和方法體。同時,也介紹了函數的各種呼叫方式、參數傳遞方式和返回值類型。讀者可以通過本章節,深入理解 C# 中函數的使用和應用。
Thumbnail
在Python中,我們可以用def關鍵字定義函數,並透過函數名稱呼叫它。函數參數可以是必填、關鍵字、默認或不定長度的類型。return語句負責結束函數並回傳值。全域變數可以在整個程序中使用,而區域變數只能在特定函數內使用。我們還可以在一個文件中定義函數,然後在另一個文件中呼叫它。
Thumbnail
在Python中,我們可以用def關鍵字定義函數,並透過函數名稱呼叫它。函數參數可以是必填、關鍵字、默認或不定長度的類型。return語句負責結束函數並回傳值。全域變數可以在整個程序中使用,而區域變數只能在特定函數內使用。我們還可以在一個文件中定義函數,然後在另一個文件中呼叫它。
Thumbnail
👨‍💻簡介 套件(Package)在Golang中扮演著組織和管理程式碼的重要角色。 package就像工具箱一樣,裡面裝滿各種不同的工具,每個工具都有特定的功能。這些工具能夠幫助你完成不同的任務,從修理家具到蓋小屋,樣樣都行。
Thumbnail
👨‍💻簡介 套件(Package)在Golang中扮演著組織和管理程式碼的重要角色。 package就像工具箱一樣,裡面裝滿各種不同的工具,每個工具都有特定的功能。這些工具能夠幫助你完成不同的任務,從修理家具到蓋小屋,樣樣都行。
Thumbnail
👨‍💻簡介 在 Go 語言中,函數(Function)是一個強大且重要的概念,就像食譜一樣,告訴你應該如何處理食材,最後得到一道美味的料理。經過哪些程序讓程式更有組織性和可讀性。函數可幫助你將程式碼區塊組織成可重複使用的元件,進而執行特定的任務。
Thumbnail
👨‍💻簡介 在 Go 語言中,函數(Function)是一個強大且重要的概念,就像食譜一樣,告訴你應該如何處理食材,最後得到一道美味的料理。經過哪些程序讓程式更有組織性和可讀性。函數可幫助你將程式碼區塊組織成可重複使用的元件,進而執行特定的任務。
Thumbnail
👨‍💻簡介 在 Go 語言中,有著一個強大又便捷的工具,可以讓你以鍵-值(Key-Value)的形式儲存和查詢資料,它就是「Map」。Map 在 Go 語言中扮演了重要的角色,簡化了許多資料處理的任務,現在讓我們一起來深入了解這個有趣的資料型別。 Map的基本概念 Map 是 Go 語
Thumbnail
👨‍💻簡介 在 Go 語言中,有著一個強大又便捷的工具,可以讓你以鍵-值(Key-Value)的形式儲存和查詢資料,它就是「Map」。Map 在 Go 語言中扮演了重要的角色,簡化了許多資料處理的任務,現在讓我們一起來深入了解這個有趣的資料型別。 Map的基本概念 Map 是 Go 語
Thumbnail
運用 Golang 正則表達式處理文本。從替換操作到 URL 解析,再到日誌分析,掌握實際應用場景下的正則技巧,提取、轉換和分析文本數據。
Thumbnail
運用 Golang 正則表達式處理文本。從替換操作到 URL 解析,再到日誌分析,掌握實際應用場景下的正則技巧,提取、轉換和分析文本數據。
Thumbnail
👨‍💻簡介 在這篇文章裡,會簡單介紹幾個關鍵的基本概念和語法結構,加快上手這門程式語言。
Thumbnail
👨‍💻簡介 在這篇文章裡,會簡單介紹幾個關鍵的基本概念和語法結構,加快上手這門程式語言。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News