🚀 Golang 函數:從入門到精通

更新於 2023/08/29閱讀時間約 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
17會員
83內容數
golang
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
Alan的開發者天地 的其他內容
👨‍💻簡介 在 Go 語言中,有著一個強大又便捷的工具,可以讓你以鍵-值(Key-Value)的形式儲存和查詢資料,它就是「Map」。Map 在 Go 語言中扮演了重要的角色,簡化了許多資料處理的任務,現在讓我們一起來深入了解這個有趣的資料型別。 Map的基本概念 Map 是 Go 語
👨‍💻簡介 在 Go 語言中,切片(Slice)是一種動態序列的資料結構,能夠方便地存儲和操作多個相同類型的元素。切片相比於陣列,更具有彈性,因為它的大小是可變的,可以根據需要動態增長或縮小。切片在處理集合型資料時非常實用,讓你能夠輕鬆地新增、刪除、修改和操作元素。
👨‍💻簡介 陣列就像是一個儲存相同類型資料的容器,你可以想像成裝滿了一樣東西的盒子,每個東西都叫做陣列元素。這種類型可以是基本的,像是整數或字串,也可以是你自己定義的型別。不過陣列有個限制,就是大小一旦確定就無法改變。在Go語言裡,陣列的長度也是型別的一部分。
👨‍💻簡介 本文簡單介紹了 Go 語言的流程控制概念,涵蓋了從條件語句到迴圈,再到 range 遍歷數據結構,以及 goto 與標籤 label 的應用。主要知識點為如何使用 if 語句進行條件判斷,以及在不同情況下運用 switch 語句。
👨‍💻簡介 本文快速介紹了 Go 語言中的各種運算符,從數學計算到邏輯判斷,包括自增自減、賦值、比較和位運算。透過實例和清晰的解釋,快速掌握如何在程式中運用這些運算符。
👨‍💻簡介 Go 語言有各種資料型別,分為基本型別和複合型別。基本型別包括: 整數、浮點數、布林值、字串 複合型別包括: 陣列、片段、結構、函式、對映、通道、介面 等。 整數型別 整數型別有許多種,像是 int8、int16、int32、int64。我們可以依據實際需求選擇。
👨‍💻簡介 在 Go 語言中,有著一個強大又便捷的工具,可以讓你以鍵-值(Key-Value)的形式儲存和查詢資料,它就是「Map」。Map 在 Go 語言中扮演了重要的角色,簡化了許多資料處理的任務,現在讓我們一起來深入了解這個有趣的資料型別。 Map的基本概念 Map 是 Go 語
👨‍💻簡介 在 Go 語言中,切片(Slice)是一種動態序列的資料結構,能夠方便地存儲和操作多個相同類型的元素。切片相比於陣列,更具有彈性,因為它的大小是可變的,可以根據需要動態增長或縮小。切片在處理集合型資料時非常實用,讓你能夠輕鬆地新增、刪除、修改和操作元素。
👨‍💻簡介 陣列就像是一個儲存相同類型資料的容器,你可以想像成裝滿了一樣東西的盒子,每個東西都叫做陣列元素。這種類型可以是基本的,像是整數或字串,也可以是你自己定義的型別。不過陣列有個限制,就是大小一旦確定就無法改變。在Go語言裡,陣列的長度也是型別的一部分。
👨‍💻簡介 本文簡單介紹了 Go 語言的流程控制概念,涵蓋了從條件語句到迴圈,再到 range 遍歷數據結構,以及 goto 與標籤 label 的應用。主要知識點為如何使用 if 語句進行條件判斷,以及在不同情況下運用 switch 語句。
👨‍💻簡介 本文快速介紹了 Go 語言中的各種運算符,從數學計算到邏輯判斷,包括自增自減、賦值、比較和位運算。透過實例和清晰的解釋,快速掌握如何在程式中運用這些運算符。
👨‍💻簡介 Go 語言有各種資料型別,分為基本型別和複合型別。基本型別包括: 整數、浮點數、布林值、字串 複合型別包括: 陣列、片段、結構、函式、對映、通道、介面 等。 整數型別 整數型別有許多種,像是 int8、int16、int32、int64。我們可以依據實際需求選擇。
你可能也想看
Google News 追蹤
Thumbnail
徵的就是你 🫵 超ㄅㄧㄤˋ 獎品搭配超瞎趴的四大主題,等你踹共啦!還有機會獲得經典的「偉士牌樂高」喔!馬上來參加本次的活動吧!
Thumbnail
隨著理財資訊的普及,越來越多台灣人不再將資產侷限於台股,而是將視野拓展到國際市場。特別是美國市場,其豐富的理財選擇,讓不少人開始思考將資金配置於海外市場的可能性。 然而,要參與美國市場並不只是盲目跟隨標的這麼簡單,而是需要策略和方式,尤其對新手而言,除了選股以外還會遇到語言、開戶流程、Ap
Thumbnail
行銷人的專屬活動,面對AI時代的行銷挑戰,我們誠摯邀請您參加一場將帶給您前所未有洞察和啟發的線上講座。 講座中將深入探討【AI語音辨識技術結合數據分析】在企業中的應用和優勢,以及如何運用【數據驅動的SEO】策略來提升網站排名,並吸引更多有價值的客戶流量。
🎯 追求職業進階?踏上專業之路?我們的短期課程絕對是你的首選!🎓 📚 抖音短視頻課程,讓你從零基礎到專業級!快節奏、輕鬆學習,一分鐘了解你所需! 🌟 課程亮點: ✅ 由資深導師執教,專業實力強大! ✅ 知識點幹貨滿滿,絕不浪費一秒! ✅ 靈活學習,隨時隨地掌握技能! ✅ 學習成果即時見證
Thumbnail
現股當沖,就是當日買進股票,當日反向賣出;當日賣出的股票,當日反向買回,不留倉。大家都很喜歡現股當沖,🎲可能是因為有博弈的快感,🫀或是有數字跳動的舒壓、悸動,加入當沖的投資人,越來越多,如滾滾黃河般綿延不絕。   📖投資人會很好奇,怎麼樣才可以進行當沖呢,很簡單,只要 🪧開戶滿3個
Thumbnail
👉關注愛麗絲,投資小意思👈 人工智能已迅速成為餐桌上和公司董事會的熱門話題。但從人工智能中獲得商業利益需要時間。投資者應謹慎行事。
Thumbnail
大自然是我们的归宿,探索自然也是我们漫漫人生的必要之一。近期,我读了一本新书——《随风去野》,是一个后现代风格的探险故事。书中的主人公辞掉工作,独自前往荒野求生存,自此开始了她的一次探险之旅。 🍃看着主人公和她面临的各种自然环境,我惊叹于自然的奇妙之处,书中呈现出的美丽景象真的很感人。我仿佛也亲
Thumbnail
受去年FED瘋狂升息影響下 債券殖利率維持在金融海嘯以來的高檔 升息促使大批投資人拋售美國公債 公債票面價格下跌 讓10年期公債殖利率跳升 投資價值已浮現 從矽谷銀行倒閉後 今年停止升息的機會極大 也許年尾還會降息 債券風險也是有 如果聯準會一路鷹到底死不降息甚至續升息 如2021~2022年持有債
Thumbnail
💡想擁有一個高含金量的網站嗎?那就來看看現在正在競標中的熱門網域吧!這些域名可是有品牌、有歷史、有潛力的哦!現在起只需 $55 起,你就能夠擁有這些域名中的一個!趕緊下標,搶住這個難得的機會,開始你的賺錢之旅吧!💰💰
Thumbnail
徵的就是你 🫵 超ㄅㄧㄤˋ 獎品搭配超瞎趴的四大主題,等你踹共啦!還有機會獲得經典的「偉士牌樂高」喔!馬上來參加本次的活動吧!
Thumbnail
隨著理財資訊的普及,越來越多台灣人不再將資產侷限於台股,而是將視野拓展到國際市場。特別是美國市場,其豐富的理財選擇,讓不少人開始思考將資金配置於海外市場的可能性。 然而,要參與美國市場並不只是盲目跟隨標的這麼簡單,而是需要策略和方式,尤其對新手而言,除了選股以外還會遇到語言、開戶流程、Ap
Thumbnail
行銷人的專屬活動,面對AI時代的行銷挑戰,我們誠摯邀請您參加一場將帶給您前所未有洞察和啟發的線上講座。 講座中將深入探討【AI語音辨識技術結合數據分析】在企業中的應用和優勢,以及如何運用【數據驅動的SEO】策略來提升網站排名,並吸引更多有價值的客戶流量。
🎯 追求職業進階?踏上專業之路?我們的短期課程絕對是你的首選!🎓 📚 抖音短視頻課程,讓你從零基礎到專業級!快節奏、輕鬆學習,一分鐘了解你所需! 🌟 課程亮點: ✅ 由資深導師執教,專業實力強大! ✅ 知識點幹貨滿滿,絕不浪費一秒! ✅ 靈活學習,隨時隨地掌握技能! ✅ 學習成果即時見證
Thumbnail
現股當沖,就是當日買進股票,當日反向賣出;當日賣出的股票,當日反向買回,不留倉。大家都很喜歡現股當沖,🎲可能是因為有博弈的快感,🫀或是有數字跳動的舒壓、悸動,加入當沖的投資人,越來越多,如滾滾黃河般綿延不絕。   📖投資人會很好奇,怎麼樣才可以進行當沖呢,很簡單,只要 🪧開戶滿3個
Thumbnail
👉關注愛麗絲,投資小意思👈 人工智能已迅速成為餐桌上和公司董事會的熱門話題。但從人工智能中獲得商業利益需要時間。投資者應謹慎行事。
Thumbnail
大自然是我们的归宿,探索自然也是我们漫漫人生的必要之一。近期,我读了一本新书——《随风去野》,是一个后现代风格的探险故事。书中的主人公辞掉工作,独自前往荒野求生存,自此开始了她的一次探险之旅。 🍃看着主人公和她面临的各种自然环境,我惊叹于自然的奇妙之处,书中呈现出的美丽景象真的很感人。我仿佛也亲
Thumbnail
受去年FED瘋狂升息影響下 債券殖利率維持在金融海嘯以來的高檔 升息促使大批投資人拋售美國公債 公債票面價格下跌 讓10年期公債殖利率跳升 投資價值已浮現 從矽谷銀行倒閉後 今年停止升息的機會極大 也許年尾還會降息 債券風險也是有 如果聯準會一路鷹到底死不降息甚至續升息 如2021~2022年持有債
Thumbnail
💡想擁有一個高含金量的網站嗎?那就來看看現在正在競標中的熱門網域吧!這些域名可是有品牌、有歷史、有潛力的哦!現在起只需 $55 起,你就能夠擁有這些域名中的一個!趕緊下標,搶住這個難得的機會,開始你的賺錢之旅吧!💰💰