iT邦幫忙

2023 iThome 鐵人賽

DAY 16
0
Modern Web

就是個Go,我也可以啦!GOGO系列 第 16

2023鐵人賽Day 16 Go x 探討方法本質及RECEIVER

  • 分享至 

  • xImage
  •  

前面介紹了很多心法及基礎觀念,接下來我要來繼續介紹身為gopher你應該理解的方法本質
Go語言沒有面向物件的元素,像是類別,繼承...,但並不代表他不能使用相似的觀念,不過也代表可能需要換個方式去習慣這一套Go獨有的思考模式
在 Go 中,可以使用「結構體」(structs)來模擬類,而方法(methods)是關聯到結構體的函數。這些方法使用一個特殊的參數稱為「接收器」(receiver)

先來看基本語法

func (receiver T) MethodName(參數列表) (返回值列表) {
  // ...
}

在 Go 語言中,方法是與某一類型相關聯的函數。這個特定類型被稱為接收器。當一個方法被定義在接收器上,這意味著該方法已綁定到該類型,可以通過這個類型的值或者指針來調用該方法

所以你可以這樣做

var t T

t.MethodName(參數列表)

舉個例子

type Rectangle struct {
    Length, Width float64
}

// Area 方法綁定到 Rectangle 類型
func (r Rectangle) Area() float64 {
    return r.Length * r.Width
}

func main() {
    rect := Rectangle{Length: 5, Width: 4}
    fmt.Println(rect.Area()) // 輸出:20
}

go 方法具有以下特點

  • 方法名的首字母大寫表示這個方法是公開的,也就是說它可以被其他的包訪問,如果首字母是小寫,則這個方法是私有的,只能被其所在的包訪問

  • 方法定義和類型定義要在同一個package內

    • 故我們無法為原生類型(int/string...)添加方法,只能為自己定義的類型添加方法
      • 但是,你可以通過定義一個新的類型(即使該類型的底層類型是內建類型)
      type MyInt int
      
      func (m MyInt) IsEven() bool {
          return m%2 == 0
      }
      
      
    • 不能橫跨Go包為其他包內的自定義類型定義方法
  • 每個方法只有一個receiver參數,不支持多receiver參數列表,一個方法只能綁定一個基本型

    • 不支持多接收器的設計有助於保持 Go 語言的簡單性和一致性。當你看到一個方法,你總是可以清楚地知道它與哪個類型相關聯

本質

Go沒有類,所以要透過receiver組在一起

type T struct {
  a int
}

func (t T) Get() int {
  return t.a
}

func (t *T) Set(a int) int {
  t.a = a 
  return t.a
}

在 Go 裡,接收器就像是方法所屬的那個物件,他允許該方法訪問和修改物件的數據,意思也是接受器也是參數的一部分
所以我們也可以把上述程式碼等價成

func Get(t T) int{
  return t.a
}

func Set(t *T, a int) int{
  t.a = a
  return t.a
}

我們可以說,go方法的本質:當我們說一個方法綁定到一個類型時,其實質上就是這個方法將該類型的一個實例(或指向該實例的指針)作為其第一個參數

選擇正確的receiver類型

你該是要使用值接受器還是指標接受器呢?選擇使用值接收器還是指針接收器主要取決於方法的目的、結構的大小以及你想要達到的語義效果
方法的 receiver 可以是值類型或指針類型,這決定了方法是如何與它所綁定的類型的實例互動的

  • 當你看到 receiver 參數類型為 T 時:
    • 該方法使用值類型的 receiver。當該方法被調用時,它作用於類型 T 的一個副本上
      type MyType struct {
          // ... fields ...
      }
      
      func (m MyType) MyMethod() {
          // ... method body ...
      }
      
  • 當你看到 receiver 參數類型為 *T 時:
    • 方法使用指針類型的 receiver,當該方法被調用時,它作用於一個指向類型 T 的指針
    type MyType struct {
      // ... fields ...
    }
    
    func (m *MyType) MyPointerMethod() {
        // ... method body ...
    }
    

根據你的需求(例如,是否需要在方法中修改 receiver 的狀態),你可以選擇使用值類型的 receiver 還是指針類型的 receiver


上一篇
2023鐵人賽Day 15 Go 之道:從 if 的快樂路徑到 for range 的安全遊走
下一篇
2023鐵人賽Day 17 Go 方法集合決定介面實現
系列文
就是個Go,我也可以啦!GOGO30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言