golang-嵌套结构体

发布于:2025-03-19 ⋅ 阅读:(16) ⋅ 点赞:(0)

结构体嵌套

golang中没有类,他通过结构体来实现其他编程语言中类的相关功能。

具名结构体

基本语法

基本语法

golang的结构体嵌套特别简单。

type 结构体类型1 struct{
    字段 类型1
    字段 类型2
}

//这样就实现了结构体的嵌套
type 结构体类型2 struct{
    字段 类型1
    字段 类型2
    字段 结构体类型1
}

举例

package struct_knowledge

import "fmt"

type Worker struct{
	salary int
	profession string
}
//具名嵌套结构体
type Human struct{
	Name string
	Age int 
	Work Worker
}

func (w Worker) GetSalary(){
	fmt.Printf("工资为%d\n",w.salary)
}

//访问具名结构体
func VisitNestingStruct(){
	var human Human
	
    //访问字段
    /*
    	报错:human.salary undefined(type Human has no filed or method GetSalary)
    */
    //human.salary = 25
    
	//通过字段连锁访问
	human.Work.salary = 20
	fmt.Printf("结构体的实例为%v\n",human)

	//通过字面量访问
	human = Human{
		Age: 20,
		Name: "张三",
		Work: Worker{
			salary: 1000,
			profession: "no work",
		},
	}
	fmt.Printf("结构体的实例为%v\n",human)

	//通过位置赋值
	human = Human{
		"lisa",
		45,
		Worker{
			salary: 10000,
			profession: "waiter",
		},
	}
	fmt.Printf("结构体的实例为%v\n",human)

	// 调用方法
	/*
		报错:human.GetSalary undefined(type Human has no filed or method GetSalary)
	*/
	// human.GetSalary()
	human.Work.GetSalary()
}

结果

结构体的实例为struct_knowledge.Human{Name:"", Age:0, Work:struct_knowledge.Worker{salary:20, profession:""}}
结构体的实例为struct_knowledge.Human{Name:"张三", Age:20, Work:struct_knowledge.Worker{salary:1000, profession:"no work"}}
结构体的实例为struct_knowledge.Human{Name:"lisa", Age:45, Work:struct_knowledge.Worker{salary:10000, profession:"waiter"}}
工资为10000

访问规则

具名嵌套结构体的访问只能通过

嵌套结构体字段名.字段
嵌套结构体字段名.方法()

不能通过最外层结构体直接访问。

举例

type Worker struct{
	salary int
	profession string
}
//具名嵌套结构体
type Human struct{
	Name string
	Age int 
	Work Worker
}

Human实例不能直接访问Worker实例的字段或方法,需要通过

Human实例.Work.字段
Human实例.Work.方法

匿名结构体

基本语法

就是不写用字段接收嵌套结构体而是直接写类型名,例如

type 结构体类型A struct{
    字段1 类型1
    字段2 类型2
    ...
}

type 结构体类型B struct{
    字段1 类型1
    结构体类型A
}

举例

package struct_knowledge

import "fmt"

type StructA struct{
	name string
	age int 
}

type StructB struct{
	price int 
	StructA
}

func VisitStructB(){
	var st StructB
	fmt.Printf("嵌套结构体的值为%#v\n",st)
}

结果

嵌套结构体的值为struct_knowledge.StructB{price:0, StructA:struct_knowledge.StructA{name:"", age:0}}

访问规则

名称访问

匿名结构体如果我们将他按照匿名字段理解,那么他就可以解析成如下形式:

type 结构体类型A struct{
    字段1 类型1
    字段2 类型2
    ...
}

type 结构体类型B struct{
    字段1 类型1
    结构体类型A
}
//按照匿名字段理解
type 结构体类型B struct{
    字段1 类型1
    结构体A 结构体类型A
}

所以我们仍然可以通过如下形式修改和访问:

结构体B实例.结构体A.字段
结构体B实例.结构体A.方法()

举例

package struct_knowledge

import "fmt"

type StructA struct{
	name string
	age int 
}

type StructB struct{
	price int 
	StructA
}

/*
	我们可以按照访问具名结构体的方法访问
	匿名结构体的名字就是 类型同名
*/
func VisitStructByName(){
	var st StructB

	//连锁访问
	st.StructA.age = 25
	fmt.Printf("结构体的实例为%#v\n",st)

	//字面量访问
	st = StructB{
		price: 1000,
		StructA: StructA{
			age:25,
			name:"lisi",
		},
	}
	fmt.Printf("结构体的实例为%#v\n",st)

	//位置访问
	st = StructB{
		1000,
		StructA{
			age:30,
			name:"sam",
		},
	}
	fmt.Printf("结构体的实例为%#v\n",st)
}

结果

结构体的实例为struct_knowledge.StructB{price:0, StructA:struct_knowledge.StructA{name:"", age:25}}
结构体的实例为struct_knowledge.StructB{price:1000, StructA:struct_knowledge.StructA{name:"lisi", age:25}}
结构体的实例为struct_knowledge.StructB{price:1000, StructA:struct_knowledge.StructA{name:"sam", age:30}}
直接访问

匿名结构体与具名结构体最大的不同就是:

我们可以直接通过外层结构体访问匿名结构体的字段或方法(前提没有产生同名冲突)

举例

package struct_knowledge

import "fmt"

type StructA struct{
	name string
	age int 
}

type StructB struct{
	price int 
	StructA
}

func (c StructA) GetAge(){
	fmt.Printf("StructA的年龄为%v\n",c.age)
}

func VisitStructByNoName(){
	var st StructB
	//在不出现名字冲突的情况下,外层结构体可以直接访问匿名结构体的字段和方法
	st.age = 25
	st.GetAge()
	fmt.Printf("结构体的实例为%#v\n",st)

	//但仅限于这种成员访问,字面量和位置就不适用
	/*
		报错:
		unknow field age in struct literal of type StructB
		unknow field name in struct literal of type StructB
	*/
	// st = StructB{
	// 	price: 1000,
	// 	age:30,
	// 	name:"lisa",
	// }
}

结果

StructA的年龄为25
结构体的实例为struct_knowledge.StructB{price:0, StructA:struct_knowledge.StructA{name:"", age:25}}

字段冲突

这种情况主要出现在匿名结构体中,因为同一结构体中字段唯一,所以结构体中不能出现同名字段。

但是匿名结构体嵌套后,由于他可以匿名访问,所以就产生了字段和方法冲突。

这也是匿名结构体允许具名访问的原因。

解决方案

当出现字段冲突时,访问匿名结构体的同名字段或方法需要采用具名访问。

举例

package struct_knowledge

import "fmt"

type StructOne struct{
	name string 
	age int
	price int
}

type StructTwo struct{
	name string 
	age int
}

type StructThree struct{
	name string
	StructOne
	StructTwo
}

func VisitStructThree(){
	var st StructThree
	fmt.Printf("结构体的实例为%#v\n",st)

	//访问不同名字段,可以直接匿名访问
	st.price  = 20

	/*
		但是访问同名字段或方法,就需要指明结构体
		如果最外层结构体有就访问的是最外层
	*/
	st.name = "lisa"

	/*
		如果访问同名字段或方法,
		但最外层结构体也没有就会报错

		ambiguous selector st.age
	*/
	// st.age = 25
}

结果

结构体的实例为struct_knowledge.StructThree{name:"", StructOne:struct_knowledge.StructOne{name:"", age:0, price:0}, StructTwo:struct_knowledge.StructTwo{name:"", age:0}}
结构体的实例为struct_knowledge.StructThree{name:"lisa", StructOne:struct_knowledge.StructOne{name:"", age:0, price:20}, StructTwo:struct_knowledge.StructTwo{name:"", age:0}}
冲突字段访问规则

1.如果要访问的同名字段或者方法顶层有,直接访问则采用顶层的字段或方法。

2.如果要访问的同名字段或者方法顶层没有,直接访问就会报错。

# ambiguous的中文含义:模糊不清的,模棱两可的
ambiguous selector st.xxx
解决字段冲突问题

要访问嵌套结构体的同名字段或者方法,可以采用具名访问法,例如

外层结构体实例.匿名结构体类型.字段
外层结构体实例.匿名结构体类型.方法()

网站公告

今日签到

点亮在社区的每一天
去签到