嵌入式 Go 类型中不可预见的 String() 方法交互
理解 Go 中 String() 方法行为的细微差别在工作时至关重要具有嵌入类型。考虑以下代码片段:
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) }
此代码的输出是“姓名:John Doe,年龄:35 3 Construction”。这种行为最初令人费解,可以通过检查嵌入类型如何与 String() 方法交互来解释。
嵌入类型提升
在 Go 中,嵌入类型允许包含其他类型的字段和方法。当一个类型嵌入另一个类型时,嵌入类型的字段和方法将提升为嵌入类型,其行为就像是在嵌入类型上定义的一样。在我们的示例中,Engineer 类型嵌入了 Person 和 TaxPayer 类型。
方法选择
在嵌入类型上调用 String() 方法时,默认行为是选择具有该名称的最浅(嵌套最浅)的方法。但是,如果同一深度有多个提升的 String() 方法,则选择器表达式将变得非法,从而导致编译时错误。
在提供的代码中,Person 和 TaxPayer 类型都具有 String()方法。因此,Engineer.String() 是非法选择器。因此,在打印 Engineer 值时,不会直接调用任何 String() 方法。
fmt 包字符串生成
当没有显式 String() 时为结构类型定义的方法,fmt 包依赖于默认的字符串表示形式,其中包括打印字段值。在 Engineer 结构中,这会导致输出“name: John Doe,age: 35 3 Construction.”
删除方法的效果
有趣的是,删除任一 Person .String() 或 TaxPayer.String() 解决了歧义,允许使用剩余的 String() 方法来生成字符串。这强调了在使用嵌入类型时仔细考虑方法命名约定的重要性。
结论
嵌入类型上的 String() 方法的行为强调了清晰度的需要以及定义方法时的远见。通过了解方法选择和提升的机制,开发人员可以避免不明确的选择器并确保其类型的字符串表示形式一致。
以上是Go 的 `String()` 方法如何与嵌入类型和多个提升方法一起运行?的详细内容。更多信息请关注PHP中文网其他相关文章!