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

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

/ 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 语言内嵌结构体成员名字冲突的问题和解决方法,可以作为大家处理名字冲突的参考。



目录
相关文章
|
搜索推荐 测试技术 数据库
QPS、TPS、RT、并发数、吞吐量分别是什么意思
QPS、TPS、RT、并发数、吞吐量分别是什么意思
3873 0
|
Go 数据库
golang编程语言操作GORM快速上手篇
使用Go语言的GORM库进行数据库操作的教程,涵盖了GORM的基本概念、基本使用、关联查询以及多对多关系处理等内容。
252 1
|
BI Go
Go语言复数完全攻略 复杂运算不再难!
Go语言复数完全攻略 复杂运算不再难!
597 0
|
JavaScript 测试技术 Go
Hyperledger fabric部署链码(一)打包链码
fabric部署chaincode-go(智能合约)系列之一
596 0
|
存储 负载均衡 NoSQL
【Redis系列笔记】Redis集群
集群是一种在多个计算机或服务器之间分配和管理任务的方式。它们被广泛应用于大型计算任务、数据处理、网络服务和高性能计算等领域。在Redis中,主要有以下三种集群,分别是主从集群,哨兵集群,分片集群。
511 18
|
存储 数据可视化 数据挖掘
实战案例:Pandas在金融数据分析中的应用
【4月更文挑战第16天】本文通过实例展示了Pandas在金融数据分析中的应用。案例中,一家投资机构使用Pandas加载、清洗股票历史价格数据,删除无关列并重命名,将日期设为索引。接着,数据被可视化以观察价格走势,进行基本统计分析了解价格分布,以及计算移动平均线来平滑波动。Pandas的便捷功能在金融数据分析中体现出高效率和实用性。
1165 0
|
Docker 容器
docker启动,重启,关闭命令
docker启动,重启,关闭命令
343 0
|
存储 自然语言处理 算法
【软件设计师—基础精讲笔记6】第六章 结构化开发方法
【软件设计师—基础精讲笔记6】第六章 结构化开发方法
1033 0
|
存储 SQL 关系型数据库
AnalyticDB PostgreSQL构建一站式实时数仓实践
本文介绍通过 AnalyticDB PostgreSQL 版基于实时物化视图,构建流批一体的一站式实时数仓解决方案,实现一套系统、一份数据、一次写入,即可在数仓内完成实时数据源头导入到实时分析全流程。
2703 5
AnalyticDB PostgreSQL构建一站式实时数仓实践
|
域名解析 缓存 弹性计算
如果你非要在 Kubernetes 集群中用 nscd
本文将阐述你应该优先考虑的方案、为什么不推荐 nscd、以及如何合理地在 Kubernetes 集群中使用 nscd。
2434 1
如果你非要在 Kubernetes 集群中用 nscd