说到内嵌命名冲突,他直接把我虐哭了......

简介: 说到内嵌命名冲突,他直接把我虐哭了......

/ Go 语言内嵌结构体成员名字冲突及解决方法 /


 

一、概述

在 Go 语言中,当一个结构体内嵌另一个匿名结构体时,可能会出现字段名冲突的问题。这时需要采取一定的解决方法,来解决名字冲突。本文将详细介绍 Go 语言中内嵌结构体成员名字冲突的问题及解决方法。

主要内容包括:

  • 内嵌结构体语法回顾
  • 名字冲突问题
  • 通过内嵌类型名解决冲突
  • 新增域覆盖内嵌域
  • 内嵌指针类型
  • 嵌套结构体中的冲突
  • 匿名字段按定义顺序
  • 内嵌结构改名
  • 方法集合并
  • 初始化顺序
  • 扩展阅读 - 内存布局
  • 实际应用案例
  • 一致性原则

希望通过本文可以全面了解 Go 语言中内嵌结构体的名称冲突问题,并能够进行恰当处理。


 

二、内嵌结构体语法回顾

首先简单回顾一下 Go 语言中内嵌结构体的语法:

type A struct {
  field1 int 
}
type B struct {
  A // 内嵌结构体A
  field2 int
}

结构体 B 通过嵌入匿名结构体 A 后,可以直接访问 A 的字段,这实现了字段的继承。


 

三、名字冲突问题

当内嵌的结构体 A 中与外层结构体 B 存在同名字段时,就会产生名字冲突问题:

type A struct {
  field1 int
}
type B struct {
  A 
  field1 int // 与A的field1冲突
}

这时需要采取一定的方式来解决冲突。


 

四、通过内嵌类型名解决冲突

可以通过明确指定内嵌类型名来访问内嵌字段:

type B struct {
  A
  field1 int
}
func main() {
  b := B{}
  b.A.field1 // 访问内嵌结构体的field1 
}

这可以避免名字冲突导致的困扰。


 

五、新增域覆盖内嵌域

外层结构体的新增字段会覆盖内嵌字段:

type A struct {
  field int
}
type B struct {
  A
  field int // 新增的field覆盖内嵌的field
}
func main() {
  b := B{}
  b.field = 1 // 就近访问外层的field
}


需要注意这一就近访问优先级的规则。


 

六、内嵌指针类型

如果内嵌的是指针类型,也需要通过类型名指定字段:

type A struct {
  field int  
}
type B struct {
  *A
  field int 
}
func main() {
  b := B{}
  b.A.field = 1
}

fieldname.A.field 可以访问。


 

七、嵌套结构体中的冲突

对于多层嵌套的结构体,也适用相同的处理方式:

type A struct {
  field int
}
type B struct {
  A
}
type C struct {
  B
  field int
}
func main() {
  c := C{}
  c.B.A.field = 1
}

需要按层次依次指定字段名。


 

八、匿名字段按定义顺序

同一级的多个匿名字段,按定义顺序可以直接访问:

type A struct {
  field1 int
}
type B struct {
  field2 int  
}
type C struct {
  A
  B
  field3 int
}
func main() {
  c := C{}
  c.field1 = 1 // 访问A的field
  c.field2 = 2 // 访问B的field
}

多个匿名字段不能重名,会按顺序依次访问。


 

九、内嵌结构改名

可以通过别名来消除字段冲突:

type A struct {
  field int
}
type B struct {
  A1 A
  field int 
}
func main() {
  b := B{}
  b.A1.field = 1 // Ok
}

这通过别名消除了冲突。


 

十、方法集合并

内嵌一个结构体会继承其方法集:

type A struct {}
func (A) method1() {}
type B struct {
  A
} 
var b B
b.method1() // B可以访问A的方法

同名方法会发生覆盖。这需要注意。


 

十一、初始化顺序

如果初始化依赖内嵌结构体,需要注意顺序:

type A struct {
  field int 
}
type B struct {
  A
  name A.field // 依赖A初始化
}
func newB() {
  return B{
    A: A{1}, 
    name: "Tom",
  }
}

构造函数可以很好控制初始化顺序。


 

十二、扩展阅读 - 内存布局

理解内嵌结构体的内存布局,可以更好处理冲突:

type A struct {
  a int
  b int
} 
type B struct {
  A
  c int
  d int
}
// B的内存布局
B {
  A.a
  A.b
  c 
  d
}

内嵌的 A 字段依次放入 B 对象布局中。


 

十三、实际应用案例

来看一个实际的例子,Rectangle 内嵌了 Point:

type Point struct {
  x int
  y int
}
type Rectangle struct {
  Point
  height int
  width int
}
func main() {
  r := Rectangle{Point{1, 2}, 3, 4}
  r.x = 5 // 内嵌字段
  r.height = 10 
}

访问内嵌结构体的字段时需要明确指定前缀。


 

十四、一致性原则

建议自定义结构体时保持字段名的一致性,比如:

type Person struct {
  PersonName string
  PersonAge int 
}
type Employee struct {
  Person
  CompanyName string
}

字段名有一定规则更容易处理内嵌时的名称冲突。


 

十五、总结

Go 语言内嵌结构体可能出现成员名字冲突,需要采用内嵌类型名、就近访问、别名等方式来解决名称问题。一定的命名规范也可以减少冲突。

合理处理名字冲突可以使代码更清晰可读。本文讨论并举例了 Go 语言内嵌结构体成员名字冲突的问题和解决方法,可以作为大家处理名字冲突的参考。



目录
相关文章
|
4月前
|
人工智能 开发者 UED
Devchat究竟好用在那些地方呢?
Devchat究竟好用在那些地方呢?
48 0
|
7月前
|
新零售 移动开发 JavaScript
分享74个Java源代码总有一个是你想要的
分享74个Java源代码总有一个是你想要的
76 0
|
Python
上古代码漫游记(二):把陷阱去掉了,反倒踩进了新的陷阱?
上古代码漫游记(二):把陷阱去掉了,反倒踩进了新的陷阱?
111 0
|
存储 JavaScript 前端开发
20个JS精简代码无形装逼集合,最为致命,记得收藏好
20个JS精简代码无形装逼集合,最为致命,记得收藏好
|
存储 SQL 关系型数据库
覆盖索引这回事算是整明白了
覆盖索引这回事算是整明白了
274 0
覆盖索引这回事算是整明白了
|
Unix Apache C++
给代码写注释时有哪些讲究?
给代码写注释时有哪些讲究?
169 0
给代码写注释时有哪些讲究?
|
消息中间件 存储 监控
好好写代码之命名篇——推敲
好好写代码之命名篇——推敲
112 0
|
自然语言处理 C语言
梦开始的地方
一个新手梦开始的地方
|
程序员
[爱偷懒的程序员系列]-Section 1. “懒”是一切需求的根源
一直认为“懒”推进了科技的发展,因为“懒”而促生了各种各样的需求。科技的进步加速了各种信息的交互频率,站在台面上说是因为业务需要提高效率,成本需要降低,服务需要更好。
171 0