结构体中,为什么不能嵌入非基础类型

news/2025/3/4 11:10:02/文章来源:https://www.cnblogs.com/maidongdong/p/18750099

问题:
为什么data可以这样声明,data1不能
type data struct {
*int
string
//string
}

type a *int

type data1 struct {
a
}

你的问题涉及到 Go 中匿名字段(embedded fields)和类型定义的规则。我来详细解释为什么 data 可以这样声明,而 data1 不行。


代码分析

1. data 的声明

type data struct {*int   // 匿名字段,类型是 *int,字段名是 intstring // 匿名字段,类型是 string,字段名是 string
}
  • 这里 data 是一个结构体类型,包含两个匿名字段:
    • *int:一个指向 int 的指针类型,字段名是 int
    • string:一个字符串类型,字段名是 string
  • 在 Go 中,结构体允许直接使用基本类型(如 intstring*int 等)或命名类型(如 time.Time)作为匿名字段。这是 Go 的语法规则,匿名字段的类型可以是任何有效类型(包括指针类型),字段名会自动取类型的简单名称。
  • 因此,data 的声明是合法的。

2. data1 的声明

type a *inttype data1 struct {a   // 匿名字段,类型是 a,字段名是 a
}
  • 这里你定义了一个新类型 a,它是 *int 的别名(type a *int)。
  • 然后在 data1 中将 a 作为匿名字段。
  • 表面上看,这似乎和 data 类似,但问题在于 Go 的语法和语义规则对匿名字段的初始化和使用有一些限制。

为什么 data1 不能像 data 那样声明并使用?

问题并不在于 data1 的声明本身,而是后续的使用方式可能会导致困惑。让我们逐步分析:

1. 声明本身是合法的

  • type data1 struct { a } 是合法的语法。
  • data1 中,a 是一个匿名字段:
    • 类型是 a(也就是 *int 的别名)。
    • 字段名是 a(取自类型名 a)。
  • 从语法上看,data1 的定义没有问题,和 data 类似。

2. 使用时的差异

你的问题可能是隐含在“这样声明”之后的使用方式上。假设你尝试像 data 那样初始化和操作 data1,会出现一些不同:

示例:data 的使用
x := 1
d := data{string: "hello",
}
d.int = &x // 直接通过字段名 int 赋值
fmt.Println(*d.int, d.string) // 输出:1 hello
  • d.int*int 类型的字段,可以直接赋值为 &x
  • 匿名字段 *int 的字段名是 int,访问和赋值都很直观。
示例:data1 的使用
x := 1
d1 := data1{} // 默认初始化,a 字段为 nil
d1.a = &x     // 通过字段名 a 赋值
fmt.Println(*d1.a) // 输出:1
  • d1.aa 类型的字段(a*int 的别名),可以赋值为 &x
  • 这看起来是可行的,但问题在于:如果你期望 data1 的字段名像 data 那样是 int(而不是 a),那是不可能的。

3. 字段名的差异

  • data 中,*int 的字段名是 int,因为 *int 是一个基本类型,Go 使用它的简单名称 int 作为字段名。
  • data1 中,a 是一个用户定义的类型(*int 的别名),它的字段名是 a,而不是 int
  • 如果你尝试用 d1.int = &x 来赋值,会报错:
    d1.int undefined (type data1 has no field or method int)
    
    因为 data1 中没有字段名为 int 的成员,只有字段名 a

根本原因:匿名字段的字段名规则

Go 中匿名字段的字段名取决于类型的名称:

  • 对于基本类型(如 *intstring),字段名是类型的简单名称(intstring)。
  • 对于用户定义的类型(如 type a *int),字段名是用户定义的类型名(a)。

对比

结构体 字段类型 字段名 可访问方式
data *int int d.int
data string string d.string
data1 a a d1.a
  • data 的字段名直接来源于基本类型(*int -> int)。
  • data1 的字段名来源于用户定义的类型名(a -> a),而不是 a 底层类型 *int 的名称。

假设你的困惑来源

你可能觉得 data1 应该也能像 data 那样用 d1.int 访问字段,但实际上:

  • data*int 是直接内嵌的基本类型,字段名是 int
  • data1a 是一个用户定义类型,字段名是 a,不会“继承”底层类型 *int 的名称。

如果改为:

type data1 struct {*int // 直接用 *int,而不是 a
}

那么 data1 就可以像 data 那样用 d1.int 访问字段,因为字段名会是 int


为什么 data1 的声明“不能这样”?

从你的问题来看,可能指的是以下情况:

  1. 字段名不一致的期望
    • 你可能希望 data1 的字段名是 int(像 data 那样),但由于 a 是用户定义类型,字段名变成了 a
  2. 语义预期不同
    • 如果你想让 data1 的行为完全模仿 data,直接用 *int 作为匿名字段就够了,而不需要定义 type a *int

合法但不一致的例子

type a *int
type data1 struct {a
}
x := 1
d1 := data1{a: &x} // 合法,但字段名是 a,不是 int
fmt.Println(*d1.a) // 输出:1
  • 这种声明是合法的,但字段名是 a,不像 data 那样是 int

总结

  • data 可以这样声明:因为它直接使用基本类型 *intstring 作为匿名字段,字段名分别是 intstring,符合 Go 的规则。
  • data1 不能“这样”声明的真正含义:如果你期望 data1 的字段名是 int 而不是 a,那是因为 a 是一个用户定义类型,字段名取自类型名 a,而不是底层类型 *int 的名称。

如果你的本意是让 data1 的字段名也是 int,你应该直接用 *int 而不是 a

type data1 struct {*int // 字段名是 int
}

这样 data1data 的行为就一致了。

希望这个解释解决了你的疑问!如果还有其他问题,欢迎继续讨论。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/893326.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一招学会Prometheus对接三方监控平台

文章来源:乐维社区 通过将Prometheus与不同的监控工具和服务集成,企业可以实现对更广泛资源和服务的监控,包括那些不由Prometheus原生支持的系统。这种集成不仅有助于获取更全面、深入的监控数据,还能提升故障排查和性能优化的效率,从而确保系统的稳定性和可靠性。 环境说…

Motoman机器人XRC控制柜维修

在现代工业生产中,YASKAWA机器人扮演着至关重要的角色。然而,如同所有的机械设备一样,YASKAWA机器人也会出现故障,尤其是其控制柜部分。因此,安川机器人维修工作对于保障机器人的正常运行意义非凡,这其中安川机器人控制柜维修更是关键环节。一、常见故障及解决方法1. 电源…

【域攻击】无文件落地攻击:msiexec

msiexec.exe属于系统进程,是Windows Installer的一部分,用于安装Windows Installer安装包(MSI),对系统的正常运行非常重要,一般在运行Microsoft Update安装更新或安装部分软件的时候出现,占用内存比较大,我们亦可以使用其作为无文件落地的媒介,下面举例说明: Step 1:使…

c# hosting 和 AppDomain

前言 简单介绍一下hosting 和 appdomain。 这两个东西。 正文 我们经常听说寄宿,这个寄宿是什么东西呢? 也就是我们这里要介绍的hosting。 什么是寄宿呢? 想一个问题,一个c# 的exe 程序,为啥能够启动呢?我们记得dll中是il代码。 那么肯定要加载运行时对吧。 那么为什么叫…

Dapr 简介 - 分布式应用运行时

Dapr 简介-分布式应用运行时 简介 Whats Dapr? Dapr = Distributed Application Runtime (分布式应用运行时)看到这个词,不知道大家想到了什么?是不是类似于 java runtime,c runtime 这类词汇。网上找到了一个 应用程序、运行时库和 OS 之间的关系图,其中 Runtime 库处于…

Mac脚本发布PHP开发项目到线上

环境 服务器: CentOS Linux release 7.6.1810 (Core) 客户端: macOS Sonoma 14.1.2 (23B92) 测试环境:开发使用ftp自动上传到/www/wwwroot/dirDev文件夹自动备份并发布程序 备份/www/wwwroot/dirOnline文件夹,并将开发项目/www/wwwroot/dirDev自动同步到线上环境/www/wwwro…

Mac发布PHP开发项目到线上项目

环境 服务器: CentOS Linux release 7.6.1810 (Core) 客户端: macOS Sonoma 14.1.2 (23B92) 开发使用ftp自动上传到/www/wwwroot/dirDev文件夹自动备份并发布程序 备份/www/wwwroot/dirOnline文件夹,并将开发项目/www/wwwroot/dirDev自动同步到线上环境/www/wwwroot/dirOnli…

Windows使用技巧——查看本地ip地址

我在windows上双击一个文件,就可以直接查看我的ip地址,这是怎么做到的?步骤一:在文件夹右击,新建一个文本文档; 步骤二:双击此文档,输入以下字符:“ipconfigpause”,然后保存;步骤三:把文件重命名,把后缀更改为“bat”如下,再点“是”; 之后双击该文档,就可以…

触想对话2025智能控制与驱动发展论坛,共探中国智造新未来!

近日,由中国工控网联合SPS广州展共同举办的“2025智能控制与驱动发展论坛”在广州珠海顺利召开,触想受邀出席并发表专题演讲,围绕公司在工业物联网(IIoT)技术应用与电子制造数字化转型中的创新实践展开分享,与国内外技术专家、行业领袖及产业链代表,共同探讨中国制造的未来…

B150平台的最后一舞 CC150上机作业

简单介绍一下CC150 大船靠岸,CC150也从24年4月的五百多元逐步降价到8月的310元(个别有299),价格基本稳定了下来,性价比日益凸显。 网传这颗CC150是NVIDIA用在GeForceNow云游戏平台上的专门向Intel定制的处理器,猜测是用在虚拟化场景。这颗处理器优劣很鲜明:优点是核心数…

Qt/C++地图组件在视频监控系统中的应用/显示设备点/弹出视频画面/调整设备位置

一、前言说明 监控系统中一般有很多的摄像头点位,除了在平面图中展示位置以外,有些工地和集团,在集中管理的地方,还希望在电子地图中展示,电子地图可以缩放和拖动,切换设备点自动放大高亮,地图自动移动到设备居中的位置,双击设备可以预览实时画面。设备的经纬度信息,在…