
结构体和匿名字段
1.结构体
Go 语言中数组切片可以存储同一类型的数据,但在结构体中可以为不同项定义不同的数据类型。
结构体是由一系列具有不同类型的数据构成的数据集合。
- 注意:结构体成员在定义时不能赋值
type 结构体名 struct { 结构体成员名 数据类型 `结构体标签` 结构体成员名 数据类型 结构体成员名 数据类型 }package main import "fmt" type Student struct { name string age int sex string score int addr string } func main() { //定义结构体变量 stu := Student{"cloud", 2, "男", 100, "北京朝阳区"} fmt.Println(stu) stu.name = "x86" fmt.Println(stu) /* C:\Users\vSphere\go\src\day03>go run 07.go {cloud 2 男 100 北京朝阳区} {x86 2 男 100 北京朝阳区} */ fmt.Printf("%p\n", &stu) fmt.Println(&stu.name) fmt.Println(&stu.age) fmt.Println(&stu.sex) fmt.Println(&stu.score) fmt.Println(&stu.addr) //结构体的地址和第一个值的地址一样 /* 0xc00001c080 0xc00001c080 0xc00001c090 0xc00001c098 0xc00001c0a8 0xc00001c0b0 */ }
2.空结构体
go语言中的struct是一种很重要的语法,里面可以存放各种字段,当然它里面也可以为空。这样可以用来单纯的做控制信息。
a := struct{}{} fmt.Println(unsafe.Sizeof(a)) // 结果: 0由于空结构体占用0字节,那么空结构体也不需要填充字节。所以空结构体组成的组合数据类型也不会占用内存空间。
type S struct { A struct{} B struct{} } var s S fmt.Println(unsafe.Sizeof(s)) // 结果: 0有一种特殊的struct{}类型的channel,它不能被写入任何数据,只有通过close()函数进行关闭操作,才能进行输出操作。struct{}类型的channel不占用任何内存。
定义:var sig = make(chan struct{})使用空 struct 是对内存更友好的开发方式,在 go 源代码中针对 空struct 类数据内存申请部分,返回地址都是一个固定的地址。那么就避免了可能的内存滥用。
- 如果定义多个空结构体都指向同一个内存地址 (全局区)
package main import ( "fmt" "unsafe" ) func main(){ //如果定义多个空结构体都指向同一个内存地址(全局区) //nill := NULL{} null1 := struct { }{} fmt.Println(unsafe.Sizeof(null1)) fmt.Printf("%p\n",&null1) null2 := struct { }{} fmt.Println(unsafe.Sizeof(null2)) fmt.Printf("%p\n",&null2) } C:\Users\vSphere\go\src\day03>go run 08.go 0 0x5a6d88 0 0x5a6d88
- 空结构体嵌套空结构体,结构体匿名字段
package main import "fmt" func main(){ type S struct { A struct{} B struct{} } s := S{} fmt.Println(s.A) fmt.Println(s.B) } C:\Users\vSphere\go\src\day03>go run 08.go {} {}
3 结构体标签
- 结构体的tag设置
type People struct { Name string `json:"name"` Age uint `json:"age"` }
- 反射
tag 是类型的一部分,主要用于通过反射获取字段的相关 tag 设置
typeOfCat := reflect.TypeOf(People{}) for i := 0; i < typeOfCat.NumField(); i++ { field := typeOfCat.Field(i) tag := field.Tag.Get("json") fmt.Println(tag) }
- 通过反射获取结构体成员
package main import ( "fmt" "reflect" ) // 在结构体操作中 结合json时,结构体成员首字母大写 type Perple struct { Name string `json:"name"` Age int `json:"age"` } func main() { //通过反射获取结构体成员 typeof := reflect.TypeOf(Perple{}) //遍历结构体成员 for i := 0; i < typeof.NumField(); i++ { field := typeof.Field(i) tag := field.Tag.Get("json") fmt.Println(tag) } }
4.结构体操作
- map中操作
package main import "fmt" type Student struct { name string age int } func main() { m := make(map[int]Student) s1 := Student{"x86", 2} s2 := Student{"cloud", 3} m[1001] = s1 //m[1003].name = "com" //不允许成员写单个操作,必须整体操作 //整体操作 m[1002] = s2 fmt.Println(m) //允许读单个操作 fmt.Println(m[1001].name, "成员读操作", m[1001].age) }
- 结构体操作
package main import "fmt" type Student struct { name string age int } func main() { //定义结构体变量 stu := Student{"女娲", 2} fmt.Println(stu) stu.name = "钟馗" stu.age = 33 fmt.Println(stu) }
5.匿名字段
可以通过匿名字段实现 “ 继承关系 ”,所谓的匿名字段就是将结构体名称作为另外结构体的成员。
继承后,子类可以直接使用父类的结构体成员。
type People struct { Name string Age uint } type Student struct { //将结构体名称作为另外结构体的成员 匿名字段 People Score int }
- 匿名字段 将结构体作为另外一个结构体成员
package main import "fmt" //子类和父类有共同的成员名 type Perple1 struct { Name string Age int } type Student1 struct { //P Perple1 //匿名字段 将结构体作为另一个结构体成员 Perple1 Name string Score int } func main(){ stu :=Student1{Perple1{"x86",2},"cloud",3} fmt.Println(stu) //子类和父类有共同的成员名,在修改同名结构体成员时采用就近原则 修改本结构体信息 stu.Name = "ops" fmt.Println(stu) //为父类结构体进行修改成员信息 stu.Perple1.Name = "dev" fmt.Println(stu) } C:\Users\vSphere\go\src\day03>go run 10.go {{x86 2} cloud 3} {{x86 2} ops 3} {{dev 2} ops 3}