Golang 结构体
优质
小牛编辑
140浏览
2023-12-01
Go 语言中的结构体和 C 语言中结构体一样,都是用来保存一组 不同类型的数据
Go 语言中的结构体和 C 语言中结构体一样,都需要先定义结构体类型再利用结构体类型定义结构体变量
定义结构体类型
type 类型名称 struct{ 属性名称 属性类型 属性名称 属性类型 ... ... }
type Studentstruct { name string age int }
创建结构体变量的两种方式
方式一:先定义结构体类型,再定义结构体变量
和 C 语言中的结构体一样,如果结构体类型需要多次使用,那么建议先定义类型再定义变量
package main import "fmt" func main() { type Student struct { name string age int } // 完全初始化 var stu1= Student{"lnj", 33} fmt.Println(stu1) // 部分初始化 // 部分初始化必须通过 属性名称: 方式指定要初始化的属性 var stu2 = Student{name:"lnj"} fmt.Println(stu2) }
方式二:定义结构体类型同时定义结构体变量(匿名结构体)
和C语言中的结构体一样,如果结构体类型只需要使用一次,那么建议定义类型同时定义变量
package main import "fmt" func main() { // 注意: 这里不用写type和结构体类型名称 var stu2 = struct { name string age int }{ name: "lnj", age: 33, } fmt.Println(stu2) }
结构体类型操作
package main import "fmt" type Student struct { name string age int } func main() { var stu= Student{"lnj", 33} // 获取结构体中某个属性对应的值 fmt.Println(stu.name) // 修改结构体中某个属性对应的值 stu.name = "zs" fmt.Println(stu) }
和 slice、map 不同的是,只要定义了结构体变量就可以使用结构体变量,默认情况下结构体中的所有属性都是属性对应类型的默认值
package main import "fmt" type Student struct { name string age int } func main() { var stu Student // 相当于 var stu = Student{} fmt.Println(stu) // { 0} stu.name = "lnj" // 不会报错 stu.age = 33 fmt.Println(stu) // {lnj 33} }
复杂结构体成员
创建时可以按照属性单独存在时初始化方式初始化
package main import "fmt" type Student struct { name string age int } func main() { type Demo struct { age int // 基本类型作为属性 arr [3]int // 数组类型作为属性 sce []int // 切片类型作为属性 mp map[string]string // 字典类型作为属性 stu Student // 结构体类型作为属性 } var d Demo = Demo{ 33, [3]int{1, 3, 5}, []int{2, 4, 6}, map[string]string{"class":"one"}, Student{ "lnj", 33, }, } fmt.Println(d) // {33 [1 3 5] [2 4 6] map[class:one] {lnj 33}} }
slice、map 类型属性默认值是 nil,不能直接使用
package main import "fmt" type Student struct { name string age int } func main() { type Demo struct { age int // 基本类型作为属性 arr [3]int // 数组类型作为属性 sce []int // 切片类型作为属性 mp map[string]string // 字典类型作为属性 stu Student // 结构体类型作为属性 } // 定义结构体变量 var d Demo // 可以直接使用基本类型属性 d.age = 33 // 可以直接使用数组类型属性 d.arr[0] = 666 // 不可以直接使用切片类型属性 //d.sce[0] = 888 // 编译报错 d.sce = make([]int, 5) // 先创建 d.sce[0] = 888 // 后使用 // 不可以直接使用字典类型属性 //d.mp["class"] = "one" // 编译报错 d.mp = make(map[string]string)// 先创建 d.mp["class"] = "one"// 后使用 // 可以直接使用结构体类型属性 d.stu.name = "lnj" fmt.Println(d) // {33 [666 0 0] [888 0 0 0 0] map[class:one] {lnj 0}} }
结构体类型转换
- 属性名、属性类型、属性个数、排列顺序都是类型组成部分
- 只有属性名、属性类型、属性个数、排列顺序都相同的结构体类型才能转换
package main import "fmt" func main() { type Person1 struct { name string age int } type Person2 struct { name string age int } type Person3 struct { age int name string } type Person4 struct { nm string age int } type Person5 struct { name string age string } type Person6 struct { age int name string gender string } var p1 Person1 = Person1{"lnj", 33} var p2 Person2 // 类型名称不一样不能直接赋值(Person1、Person2) //p2 = p1 // 虽然类型名称不一样, 但是两个类型中的`属性名称`、`属性类型`、`属性个数`、`排列顺序`都一样,所以可以强制转换 p2 = Person2(p1) fmt.Println(p2) // 两个结构体类型中的`属性名称`、`属性类型`、`属性个数`都一样,但是`排列顺序`不一样,所以不能强制转换 //var p3 Person3 //p3 = Person3(p1) //fmt.Println(p3) // 两个结构体类型中的`属性类型`、`属性个数`、`排列顺序`都一样,但是`属性名称`不一样,所以不能强制转换 //var p4 Person4 //p4 = Person4(p1) //fmt.Println(p4) // 两个结构体类型中的`属性名称`、`属性个数`、`排列顺序`都一样,但是`属性类型`不一样,所以不能强制转换 //var p5 Person5 //p5 = Person5(p1) //fmt.Println(p5) // 两个结构体类型中的`属性名称`、`属性类型`、`排列顺序`都一样,但是`属性个数`不一样,所以不能强制转换 //var p6 Person6 //p6 = Person6(p1) //fmt.Println(p6) }
匿名属性
- 没有指定属性名称,只有属性的类型,我们称之为匿名属性
- 任何
有命名的数据类型
都可以作为匿名属性(int、float、bool、string、struct 等)
package main import "fmt" func main() { type Person struct { int float32 bool string } // 不指定名称初始化 per1 := Person{3, 3.14, false, "lnj"} fmt.Println(per1) // 可以把数据类型作为名字显示初始化 per2 := Person{ int: 3, float32: 3.14, bool: true, string: "lnj", } fmt.Println(per2) // 可以把数据类型当做属性名称操作结构体 per2.int = 666 fmt.Println(per2.int) // 666 }
Go 语言中最常见的匿名属性是用 结构体类型作为匿名属性
package main import "fmt" func main() { type Person struct { name string age int } type Student struct { Person // 匿名属性 class string } stu := Student{ Person{"lnj", 33}, "学前一班", } fmt.Println(stu) // {{lnj 33} 学前一班} }
如果结构体作为匿名属性,想访问匿名属性的属性有两种方式
package main import "fmt" func main() { type Person struct { name string age int } type Student struct { Person // 匿名属性 class string } stu := Student{ Person{"lnj", 33}, "学前一班", } fmt.Println(stu) // {{lnj 33} 学前一班} // 方式一: 先找到匿名属性,再访问匿名属性中的属性 stu.Person.name = "zs" fmt.Println(stu) // {{zs 33} 学前一班} // 方式二: 直接访问匿名属性中的属性 // 系统会先查找当前结构体有没有名称叫做name的属性 // 如果没有会继续查找匿名属性中有没有名称叫做name的属性 stu.name = "ww" fmt.Println(stu) // {{ww 33} 学前一班} }
注意点:如果多个匿名属性的属性名称相同,那么不能通过方式二操作,只能通过方式一
package main import "fmt" func main() { type Person struct { name string age int } type Class struct { name string time string } type Student struct { Person // 匿名属性 Class // 匿名属性 } stu := Student{ Person{"lnj", 33}, Class{"学前一班", "2020-12-12"}, } fmt.Println(stu) // {{lnj 33} {学前一班 2020-12-12}} // 编译报错, 系统搞不清楚要找哪个name //stu.name = "zs" stu.Person.name = "zs" stu.Class.name = "小学一年级" fmt.Println(stu) // {{zs 33} {小学一年级 2020-12-12}} }
注意点:只有匿名结构体才支持向上查找
package main import "fmt" func main() { type Person struct { name string } type Student struct { per Person age int } var stu Student = Student{Person{"lnj"}, 18} //fmt.Println(stu.name) // 报错 fmt.Println(stu.per.name) // 必须通过属性进一步查找 fmt.Println(stu.age) }
注意点:如果匿名属性是一个结构体类型,那么这个结构体类型不能是自己
package main import "fmt" func main() { type Person struct { Person // 错误 name string } type Student struct { *Student // 正确, 链表 age int } }