iT邦幫忙

2024 iThome 鐵人賽

DAY 13
1
Modern Web

Go 快 Go 高效: 從基礎語法到現代Web應用開發系列 第 13

【Day13】Golang 管理程式碼邏輯 | 函數與方法(Functions & Methods)

  • 分享至 

  • xImage
  •  

在 Golang 中,管理程式碼邏輯的核心在於簡潔與清晰,這不僅提高了程式碼的可讀性,也提升了可維護性。本教學將探討如何撰寫小而精的函數以及如何合理處理參數,並理解 Golang 的包(Package)與命名規則。

  • 避免過多的參數
// FIXME: - 不好的範例:
func CreateUser(name string, age int, email string, address string, phoneNumber string) {
    // 處理使用者創建
}
// TODO: - 優化後的範例:
type User struct {
    Name        string
    Age         int
    Email       string
    Address     string
    PhoneNumber string
}

func CreateUser(user User) {
    // 處理使用者創建
}

使用 struct 讓參數結構清晰,未來也可以輕鬆擴展 User 的屬性。


匿名函數與立即執行函數(IIFE)

在 Go 語言中,除了定義命名函數外,還可以使用匿名函數(Anonymous Functions)來實現更靈活的程式設計。當匿名函數定義完成後,可以立即執行它,這種模式稱為 立即執行函數(Immediately Invoked Function Expression, IIFE)

  • 特點:

    • 封裝作用域:避免變數污染全域作用域。
    • 即時執行:在定義後立即執行特定邏輯,適用於初始化或一次性操作。
    • 模組化:將相關邏輯封裝在一個獨立的函數中,提高程式碼的可讀性與維護性。
  • 無參數的 IIFE

func() {
    fmt.Println("Hello")
}()

定義了一個無參數的匿名函數,並在定義後立即使用 () 執行它。

  • 帶參數的 IIFE
func(name string, age int) {
    fmt.Printf("姓名: %s, 年齡: %d\n", name, age)
}("Alice", 30)

定義了一個接受 nameage 兩個參數的匿名函數,並傳入 "Alice"30 作為實際參數。

  • 帶回傳值的 IIFE
result := func(a, b int) int {
    return a + b
}(5, 7)
fmt.Println("5 + 7 =", result)

定義了一個接受兩個整數參數並回傳其和的匿名函數,立即傳入 5 和 7 執行,並將結果存入變數 result

使用場景

  • 初始化設置:在程式啟動時進行一次性的設置操作。
  • 封裝變數:將變數限制在函數內部,避免與其他部分的變數衝突。
  • 即時計算:需要立即獲取計算結果並使用。

依賴倒置原則(Dependency Inversion Principle, DIP)

  • 高層模組應該依賴於抽象,而不是依賴具體實現。

  • 抽象(介面或抽象類別)不應依賴具體實作,反而具體實作應依賴抽象。

  • 高層模組應該依賴於抽象

package main

import "fmt"

// 定義 PaymentProcessor 介面
type PaymentProcessor interface {
    ProcessPayment(amount float64) bool
}

// CreditCardProcessor 實作信用卡付款
type CreditCardProcessor struct{}

func (cc CreditCardProcessor) ProcessPayment(amount float64) bool {
    fmt.Printf("信用卡付款:$%.2f\n", amount)
    return true
}

// PayPalProcessor 實作 PayPal 付款
type PayPalProcessor struct{}

func (pp PayPalProcessor) ProcessPayment(amount float64) bool {
    fmt.Printf("PayPal 付款:$%.2f\n", amount)
    return true
}

// DaiwanPayProcessor 實作 台灣Pay 付款
type DaiwanPayProcessor struct{}

func (bp DaiwanPayProcessor) ProcessPayment(amount float64) bool {
    fmt.Printf("台灣Pay 付款:$%.2f\n", amount)
    return true
}

// MakePayment 根據 PaymentProcessor 來處理付款
func MakePayment(p PaymentProcessor, amount float64) {
    success := p.ProcessPayment(amount)
    if success {
        fmt.Println("付款成功!")
    } else {
        fmt.Println("付款失敗!")
    }
}

func main() {
    // 信用卡付款
    creditCardProcessor := CreditCardProcessor{}
    MakePayment(creditCardProcessor, 100.0)

    // PayPal 付款
    paypalProcessor := PayPalProcessor{}
    MakePayment(paypalProcessor, 200.0)

    // 台灣Pay 付款
    DaiwanPayProcessor := DaiwanPayProcessor{}
    MakePayment(DaiwanPayProcessor, 300.0)
}
</* Output: */>
信用卡付款:$100.00
付款成功!
PayPal 付款:$200.00
付款成功!
台灣Pay 付款:$300.00
付款成功!

https://ithelp.ithome.com.tw/upload/images/20240918/20161850oMxIBnIwJe.png

MakePayment 是高層模組,它並沒有依賴具體的付款實現如 CreditCardProcessorPayPalProcessorDaiwanPayProcessor,而是依賴於 PaymentProcessor 介面。
這樣的設計使得程式碼更加靈活,能夠輕鬆切換或擴展不同的付款方式,而不需要修改高層邏輯(MakePayment 函數)。


跨檔案存取

Go 語言中,變數或函數是否可以被其他 package 存取,並不依靠 publicprivate 關鍵字,而是根據命名的第一個字母大小寫來決定:

  • 大寫開頭的函數、變數和類型可以被其他 package 存取(Public)。
  • 小寫開頭的函數、變數和類型則只能在相同 package 內使用(Private)。
  • 小寫命名與大寫命名的差異
// Public
var PublicVariable string
type PublicStruct struct {}
func PublicFunction() {}

// Private
var privateVariable string
type privateStruct struct {}
func privateFunction() {}
  • 跨檔案存取
myproject/
├── main.go 
└── math/  
    └── math.go

math.go

package math

// 公開的 Add 函數,可以被其他 package 匯入並使用
func Add(a int, b int) int {
    return a + b
}

main.go

package main

import (
    "fmt"
    "myproject/math" // 匯入自定義的 math package
)

func main() {
    result := math.Add(10, 5) // 使用 math package 中的 Add 函數
    fmt.Println("結果:", result)
}
  • 上面的 myproject 是我們在 go.mod 定義的模組名稱(如果忘記的話,可以去複習第二天的內容),他後面接的就是在我們專案資料夾下面我們檔案所處在的資料夾路徑
  • 在 Go 語言中,package 是程式碼的基本組織單位。不同的 package 之間,只能存取大寫開頭的公開成員(即 public 成員)。這些公開成員包括函數、變數和結構體。
    如果成員名稱是小寫開頭的,則這些成員僅能在相同的 package 中存取(即 private 成員),其他 package 無法直接使用它們。

總結

今天我們學到了以下幾點:

  1. 小而精的函數設計:使用 struct 組織參數,讓程式碼更清晰、易擴展。
  2. 匿名函數與立即執行函數(IIFE):利用匿名函數封裝邏輯並立即執行,提升程式碼的模組化與封裝性
  3. 依賴倒置原則:高層模組應依賴抽象(介面),而非具體實現,提升程式碼的靈活性與可維護性。
  4. 跨檔案與 Package 存取:Go 語言透過 package 來組織程式碼,公開成員依賴於名稱的大小寫來控制存取範圍。
    那今天基本語法就介紹到這裡,之後的內容我覺得都蠻有趣,如果看一次不懂的話,可以多看幾次,那大家就一起撐完30天吧!

上一篇
【Day12】Golang 核心語法 | 指標與記憶體管理(Pointers & Memory Management)
下一篇
【Day14】多線程/平行化處理 I | Goroutines 和 Channels
系列文
Go 快 Go 高效: 從基礎語法到現代Web應用開發30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言