亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

String() 方法在 Go 中嵌入式類型的奇怪行為

String() 方法在 Go 中嵌入式類型的奇怪行為

Go
千巷貓影 2022-08-30 15:24:06
我無法理解 String() 方法如何用于 Go 中的嵌入式結構。請考慮以下情況:type Engineer struct {    Person    TaxPayer    Specialization string}type Person struct {    Name string    Age  int}func (p Person) String() string {    return fmt.Sprintf("name: %s, age: %d", p.Name, p.Age)}type TaxPayer struct {    TaxBracket int}func (t TaxPayer) String() string {    return fmt.Sprintf("%d", t.TaxBracket)}func main() {    engineer := Engineer{        Person: Person{            Name: "John Doe",            Age:  35,        },        TaxPayer: TaxPayer{3},        Specialization: "Construction",    }    fmt.Println(engineer)}此代碼的輸出為 。但是,如果我刪除方法定義,則輸出只是(它調用)。但是,如果我也刪除方法定義,則輸出為 。我最初認為必須為整個結構定義一個隱式方法,但沒有這樣的方法。{name: John Doe, age: 35 3 Construction}Person.String()3engineer.TaxPayer.String()TaxPayer.String(){{John Doe 35} {3} Construction}String()Engineer為什么方法調用會以這種方式運行?如果我將每個嵌入式類型的方法命名為除(比如說)以外的任何東西,然后嘗試這樣做,我得到一個(預期的)編譯錯誤:。為什么在改為方法名稱時不引發此錯誤?String()Foo()fmt.Println(engineer.Foo())ambiguous selector engineer.FooString()
查看完整描述

1 回答

?
大話西游666

TA貢獻1817條經驗 獲得超14個贊

如果在結構中嵌入類型,則嵌入類型的字段和方法將提升為嵌入類型。它們“作用”就像在嵌入器類型上定義一樣。

這是什么意思?如果類型嵌入類型,并且類型有一個方法,你可以調用類型(接收方仍然是,這不是繼承也不是虛方法)。ABBString()String()AB

目前為止,一切都好。但是,如果類型嵌入了類型和類型,兩者都有一個方法呢?然后會模棱兩可,因此在這種情況下,該方法將不會被推廣。ABCString()A.String()String()

這解釋了您的經歷。打印將具有默認格式(結構字段),因為將有 2 種方法,因此沒有一個用于其自身。當然,默認格式設置涉及打印字段,并且為了生成值的默認表示形式,包會檢查正在打印的值是否實現 ,如果是,則調用其方法。EngineerString()Engineerstringfmtfmt.StringerString()

如果刪除 ,則只有一個方法被提升,from ,因此該方法由包調用以生成值本身的表示形式。Person.String()String()TaxPlayerfmtstringEngineer

同樣,如果你刪除 :那么將是唯一提升的方法,所以它用于值本身。TaxPayer.String() Person.String()String()Engineer

這在 Spec: 結構類型中有詳細說明:

如果結構中嵌入字段的字段或方法是表示該字段或方法的合法選擇器,則稱為升級。fxx.ff

[...]給定一個結構類型和一個定義的類型,升級的方法包含在結構的方法集中,如下所示:ST

  • 如果包含一個嵌入字段,則 方法 和 兩者都包括帶有接收器的提升方法。的方法集還包括帶有接收器的提升方法。STS*ST*S*T

  • 如果包含一個嵌入字段,則 的方法集 和 兩者都包括帶有 receiver 或 的升級方法。S*TS*ST*T

第一句說“如果x.f是法定選擇器”。法律是什么意思?

規格: 選擇器:

對于不是包名稱的主表達式選擇器表達式x

x.f

表示值 的字段或方法。fx

[...]選擇器可以表示某種類型的字段或方法,也可以引用 嵌套嵌入字段 的字段或方法。遍歷以達到的嵌入場的數量稱為 其深度在 中。中聲明的字段或方法的深度為零。在 嵌入的字段中聲明的字段或方法 f 的深度是 in 加一的深度。ffTfTfTfTATfA

以下規則適用于選擇器:

  • 對于類型或 where 的值不是指針或接口類型,表示存在此類 .如果深度不正好有一個 f,則選擇器表達式是非法的。xT*TTx.fTf

  • [...]

強調了本質,并解釋了為什么首先沒有調用任何方法:可能來自2個“源”:和,因此是非法的選擇器,因此沒有一個方法將是方法集的一部分。String()Engineer.String()Person.StringTaxPayer.StringEngineer.StringString()Engineer

使用非法選擇器會引發編譯時錯誤(例如“不明確的選擇器工程師。福”)。因此,您收到錯誤,因為您顯式嘗試引用 。但是僅僅嵌入2種類型都有,這不是編譯時錯誤。嵌入本身不是錯誤。使用非法選擇器將是錯誤。如果你寫 ,那會再次引發編譯時錯誤。但是如果你只是通過打?。?,這里沒有非法的選擇器,你就不參考了。這是允許的。(當然,由于方法集 沒有提升的方法,因此只有在打印字段時才會調用它來生成 – 的字符串表示形式。engineer.FooString()engineer.String()engineerfmt.Println(engineer)engineer.String()EngineerString()Engineer


查看完整回答
反對 回復 2022-08-30
  • 1 回答
  • 0 關注
  • 113 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號