首頁 >後端開發 >Golang >為什麼 fmt.Println 在傳遞基於值的物件時不呼叫我的 Stringer 介面的 String 方法?

為什麼 fmt.Println 在傳遞基於值的物件時不呼叫我的 Stringer 介面的 String 方法?

Susan Sarandon
Susan Sarandon原創
2024-12-06 19:35:15493瀏覽

Why Doesn't fmt.Println Invoke My Stringer Interface's String Method When Passing a Value-Based Object?

Stringer 接口與Println 的混淆:理解基於值與基於指針的對象

問題:

在物件實作了Stringer介面的場景下,為什麼不如果物件是基於值的,那麼使用fmt.Println 時會呼叫物件的 String 方法嗎?

程式碼範例:

考慮以下 Go 程式碼:

type Car struct {
    year int
    make string
}

func (c *Car) String() string {
    return fmt.Sprintf("{make:%s, year:%d}", c.make, c.year)
}

func main() {
    myCar := Car{year: 1996, make: "Toyota"}
    fmt.Println(myCar)
}

當 myCar 是指標時,String 方法會按預期呼叫。但是,當 myCar 是一個值時,就會使用預設的 Go 格式。

答案:

此行為的原因在於 Go 介面的工作方式。當您指定實作介面的類型(在本例中為 Stringer)時,Go 會期望該類型是介面的確切類型。當您將Car類型的值傳遞給fmt.Println時,它會隱式轉換為interface{},並且interface{}類型系統中沒有Car類型。相反,它是 *Car 類型(指向 Car 的指標)。

fmt.Println 函數使用類型開關來決定如何根據其類型列印值。對於 Stringer 接口,它檢查該值是否實作 String 方法。由於 Car(基於值)不實作 String,因此使用預設格式。但是,當您明確呼叫 myCar.String() 時,編譯器會自動將其轉換為 (&myCar).String(),它具有正確的 *Car 類型並呼叫所需的格式化方法。

以確保無論其類型如何,物件都會根據需要進行格式化,您有兩個選擇:

  1. 在汽車上實現字串(基於值): 這需要為Car 建立一個單獨的String 方法來操作值接收器,這會導致不必要的物件複製。
  2. 始終傳遞一個指向fmt.Println 的指標: 透過使用fmt.Println(&myCar),您可以確保傳遞的值具有正確的*Car 類型,並且String 方法將被呼叫為預計。

以上是為什麼 fmt.Println 在傳遞基於值的物件時不呼叫我的 Stringer 介面的 String 方法?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn