Go结构体字段定义

结构体字段定义的两种方式:普通字段声明与嵌入字段

先创建一个结构体Student,Student具有两个方法:Hello()以及Grow() ,Hello()是一个值接收者方法 ,Grow()是一个指针接收者方法

go 复制代码
type Student struct{
	Name string
	Age int
}

func(student Student) Hello(){
	fmt.Printf("你好, 我是%s,今年%d岁\n",student.Name,student.Age)
}
func(student *Student) Grow(){
	student.Age++
}

再创建一个接口StudentInterface 以及GrowOne()函数,显然Student 是实现了StudentInterface

scss 复制代码
type StudentInterface interface{
	Hello()
	Grow()
}
func GrowOne(studentInterface StudentInterface){
	studentInterface.Hello()
	studentInterface.Grow()
	studentInterface.Hello()
}

普通字段声明

再创建一个结构体Person ,这里使用普通字段声明Student

go 复制代码
type Person struct{
	Student Student
	Address string
}

对于普通字段声明,Student的方法和字段完全与Person无关:

1.Person不能直接调用Hello()和Grow()方法,必须通过person.Student来调用这两个方法 2.Person没有实现StudentInterface接口

3.Person不具备Student的字段

嵌入字段

嵌入字段是Go实现组合(而非继承)的核心特性。在使用嵌入字段时,有两种情况:使用T嵌入 和使用*T嵌入

使用T嵌入

修改结构体Person,T嵌入的本质是嵌入一个

go 复制代码
type Person struct{
	Student
	Address string
}
初始化

在Person被创建的时候,即使不给Student赋值,也会分配一个Student的零值类型

css 复制代码
func main() {
	person:=Person{
		Address: "上海",
	}
	GrowOne(&person.Student)
}

输出结果为:

复制代码
你好, 我是,今年0岁
你好, 我是,今年1岁

很明显,Student中的Name字段是string类型,被赋予零值"",Age字段是int,被赋予零值0

方法提升和字段提升

Student的值接收者方法和其字段会被提升到Person,如图所示:

但是为什么Grow()方法是一个指针接收者方法,而person.Grow()不会报错呢?

原因在于Go语言在调用方法时有一个重要的特性:自动解引用/取地址 机制。 通过一个变量调用方法时,Go编译器会自动进行必要的地址操作,以匹配方法的接收者类型。

scss 复制代码
person.Grow()          // Go会自动转换为:(&person.Student).Grow()

下面来证明person实际是不拥有Grow()这个方法的:

方法1

先假设person拥有Grow()这个方法,那么此时person同时拥有Hello()和Grow(),这意味着person实现了StudentInterface接口。

但实际上perso并不是StudentInterface,因此person实际上是不拥有Grow()的。

方法2

还有可以通过另一种方式证明,并引出go中字面量的特性

通过person的字面量调用Grow()和Hello(),会发现调用Grow()时报错,其原因还是

scss 复制代码
Person{...}.Grow() // Go会自动转换为:(&Person{...}.Student).Grow()

但是Person{...}是一个字面量,但在 Go 语言中,复合字面量(如结构体、数组、切片、map的字面量)在直接使用时是不可寻址的 ,字面量代表的是一个,而不是一个变量。因此Go直接禁止了字面量的寻址。

使用*T嵌入

修改结构体Person,*T嵌入本质是嵌入一个指针

go 复制代码
type Person struct{
	*Student
	Address string
}
初始化

需要注意的一点是,因为*T嵌入是嵌入一个指针,因此在初始化Person时未设置Student字段的值,那么其将是一个空指针nil。

方法提升和字段提升

Student中的所有字段以及所有方法将会提升到Person中,被Person所拥有

person拥有Hello()以及Grow()因此person此时实现了StudentInterface接口

总结

  1. 在结构体中使用普通字段 声明,字段的字段和方法与结构体无关 ,必须通过字段来间接调用
  2. 在结构体中使用T嵌入字段 时,T的字段和值接收方法被结构体所拥有
  3. 在结构体中使用*T嵌入字段 时,T的所有和所有方法都被结构体所拥有
相关推荐
2301_816997885 小时前
Go语言开发环境搭建
go
2301_816997886 小时前
Go语言简介
golang·go
KeithChu1 天前
Go 语言中的 slice 类型
go
追随者永远是胜利者2 天前
(LeetCode-Hot100)253. 会议室 II
java·算法·leetcode·go
追随者永远是胜利者2 天前
(LeetCode-Hot100)207. 课程表
java·算法·leetcode·go
追随者永远是胜利者2 天前
(LeetCode-Hot100)169. 多数元素
java·算法·leetcode·go
追随者永远是胜利者2 天前
(LeetCode-Hot100)226. 翻转二叉树
java·算法·leetcode·职场和发展·go
追随者永远是胜利者2 天前
(LeetCode-Hot100)200. 岛屿数量
java·算法·leetcode·职场和发展·go
追随者永远是胜利者2 天前
(LeetCode-Hot100)301. 删除无效的括号
java·算法·leetcode·职场和发展·go