【11.0】Go语言基础之结构体

【一】什么是结构体

  • 结构体是用户定义的类型,表示若干个字段(Field)的集合。
    • 有时应该把数据整合在一起,而不是让这些数据没有联系。
    • 这种情况下可以使用结构体。
  • 例如,一个职员有firstName 、 lastName和age 三个属性,而把这些属性组合在一个结构体employee中就很合理。

【二】结构体的定义和使用

【1】结构体语法

type 名字 struct{ 字段1 类型 字段2 类型 } // 定义了一个结构体,用户自定义的类型 type Person struct { name string age uint8 sex string hobby []string }

【2】结构体的定义与使用

package main import "fmt" // 结构体 : //结构体是用户定义的类型,表示若干个字段(Field)的集合。 //有时应该把数据整合在一起,而不是让这些数据没有联系。这种情况下可以使用结构体 // 结构体的标准语法 /* type 名字 struct{ 字段1 类型 字段2 类型 } */ // [1]定义了一个结构体,用户自定义的类型 type Person struct { name string age uint8 sex string hobby []string } func main() { // [2]使用结构体 var person Person // 结构体是值类型 : 定义没有初始化,打印后有值 fmt.Println("这是定义的结构体 :>>>> ", person) // 这是定义的结构体 :>>>> { 0 []} }

【3】结构体初始化

package main import "fmt" // [1]定义了一个结构体,用户自定义的类型 type Person struct { name string age uint8 sex string hobby []string // 切片类型 } func main() { // [2]使用结构体并且始化 var person Person = Person{} fmt.Println("这是定义的结构体无值传入 :>>>> ", person) // 这是定义的结构体无值传入 :>>>> { 0 []} hobby := make([]string, 3, 4) var person1 Person = Person{"Dream", 18, "男", hobby} // 按位置传参,符合顺序,并且不能少传参数 fmt.Println("这是定义的结构体有值传入 :>>>> ", person1) // 这是定义的结构体有值传入 :>>>> {Dream 18 男 [ ]} var person2 Person = Person{name: "Dream", age: 18, sex: "男"} // 不按位置传参,可以不符合顺序,并且可以少传参数 fmt.Println("这是定义的结构体有值传入 :>>>> ", person2) // 这是定义的结构体有值传入 :>>>> {Dream 18 男 []} }

【4】结构体使用

package main import "fmt" // [1]定义了一个结构体,用户自定义的类型 type Person struct { name string age uint8 sex string hobby []string // 切片类型 } func main() { // [2]使用结构体并且始化 hobby := make([]string, 3, 4) var person Person = Person{"Dream", 18, "男", hobby} // 按位置传参,符合顺序,并且不能少传参数 fmt.Println("这是定义的结构体有值传入 :>>>> ", person) // 这是定义的结构体有值传入 :>>>> {Dream 18 男 [ ]} // 结构体的使用 // 取值 fmt.Println("这是取值并打印 :>>>> ", person.name) // 这是取值并打印 :>>>> Dream // 修改值 person.name = "Hope" fmt.Println("这是修改值并打印 :>>>> ", person.name) // 这是修改值并打印 :>>>> Hope // 增加值 ---> 切片类型,必须先初始化才能使用 person.hobby[0] = "音乐" // 会报错,越界。切片只能按长度的下标取值,不能按容量的下标取值 // person.hobby[3] = "乒乓球" // panic: runtime error: index out of range [3] with length 3 // append 追加值 person.hobby = append(person.hobby, "乒乓球") fmt.Println("这是增加值并打印 :>>>> ", person.hobby) // 这是增加值并打印 :>>>> [音乐 乒乓球] }

【5】创建匿名结构体

package main func main() { // 创建匿名结构体 ---> 结构体没有名字 ----> 一般定义在函数内部 ----> 只使用一次 // 没有 type 和 名字 p := struct { name string age int }{ // 定义匿名结构体并初始化 name: "Dream", age: 18, } }

【6】结构体的零值

package main import "fmt" type Person struct { name string age uint8 sex string hobby []string // 切片类型 } func main() { // 结构体 的零值 --- 结构体是值类型 --- 空值不为 nil , 是每个结构体参数类型的零值 var person Person fmt.Println("结构体 person 的零值 :>>>> ", person) // 结构体 person 的零值 :>>>> { 0 []} }

【7】结构体当函数参数传递

package main import "fmt" type Person struct { name string age uint8 sex string hobby []string // 切片类型 } func main() { // 结构体作为函数参数 var person Person fmt.Println("结构体 person 的初识值 :>>>> ", person) // 调用函数 --- 值类型当参数传递不会影响原来的值 index(person) fmt.Println("调用函数后 ,结构体 person 的初识值 :>>>> ", person) //结构体 person 的初识值 :>>>> { 0 []} //这是在函数内部修改过后的结构体 :>>>> {梦梦 0 []} //调用函数后 ,结构体 person 的初识值 :>>>> { 0 []} } func index(p Person) { p.name = "梦梦" fmt.Println("这是在函数内部修改过后的结构体 :>>>> ", p) }

【8】访问结构体字段

package main import "fmt" type Person struct { name string age uint8 sex string hobby []string // 切片类型 } func main() { // 访问结构体字段 : 通过 . 访问,如果结构体某个字段是引用类型,引用类型必须要初始化 var person Person = Person{name: "Dream", age: 18} fmt.Println("访问 结构体 person 的值 :>>>> ", person.name) fmt.Println("访问 结构体 person 的值 :>>>> ", person.age) //访问 结构体 person 的值 :>>>> Dream //访问 结构体 person 的值 :>>>> 18 }

【9】匿名字段

package main import "fmt" func main() { // 匿名字段 ----> 字段没有名字 ----> 匿名字段类型不能重复 , 可以和有名字段混合使用 type Animal struct { string // 定义了字段类型,但是字段没有名字 int // 类型名就是字段名 } // 初始化结构体 // 按位置赋初值 var animal Animal = Animal{"梦梦", 18} fmt.Println("这是初始化后的 结构体 animal :>>>> ", animal) // 这是初始化后的 结构体 animal :>>>> {梦梦 18} // 按关键字赋初值 -- 如果没有字段名,则类型名就是字段名 var animal1 Animal = Animal{string: "蚩梦", int: 19} fmt.Println("这是初始化后的 结构体 animal1 :>>>> ", animal1) // 这是初始化后的 结构体 animal1 :>>>> {蚩梦 19} // 字段取值 fmt.Println("结构体 animal 的取值 :>>>> ", animal1.string) // 结构体 animal 的取值 :>>>> 蚩梦 }

【10】结构体嵌套

(1)结构体嵌套有名结构体

package main import "fmt" func main() { // 结构体嵌套 --- 结构体中套结构体 type Duck struct { name string age int } type Chick struct { name string height float32 duck Duck // 可以是自己定义的结构体 } // 结构体初始化 var chick Chick = Chick{name: "战斗鸡", height: 88, duck: Duck{name: "战斗鸭", age: 99}} fmt.Println("这是结构体初始化后的 chick :>>>> ", chick) // 这是结构体初始化后的 chick :>>>> {战斗鸡 88 {战斗鸭 99}} // 结构体的取值 fmt.Println("这是结构体的取值 :>>>> ", chick.duck.name) // 这是结构体的取值 :>>>> 战斗鸭 }

(2)结构体嵌套匿名结构体

package main import "fmt" func main() { // 结构体嵌套 --- 结构体中套结构体 type Chick struct { name string height float32 // 可以是自己定义的结构体 --- 匿名结构体 duck struct { name string age int } } // 结构体初始化 var chick Chick = Chick{name: "战斗鸡", height: 88} chick.duck.name = "战斗鸭" chick.duck.age = 66 fmt.Println("这是结构体初始化后的 chick :>>>> ", chick) // 这是结构体初始化后的 chick :>>>> {战斗鸡 88 {战斗鸭 66}} }

【11】字段提升

package main import "fmt" func main() { // 结构体嵌套 + 匿名字段 --- 字段提升 type Duck struct { name string age int } type Chick struct { name string height float32 Duck } // 结构体初始化 var chick Chick = Chick{name: "战斗鸡", height: 88, Duck: Duck{name: "战斗鸭", age: 66}} fmt.Println("这是结构体初始化后的 chick :>>>> ", chick) // 这是结构体初始化后的 chick :>>>> {战斗鸡 88 {战斗鸭 66}} // 取值 fmt.Println("取出内层结构体的值 :>>>> ", chick.Duck.name) // 字段提升,本来是 Duck 的字段,但是提升到了 Chick 身上 // 但是字段名重复就不能再提升了 fmt.Println("取出内层结构体的值 :>>>> ", chick.name) // 字段提升类似于面向对象的继承 ----> 相当于 Chick 继承了 Duck ----> 子类中调用父类的属性 ----> 子类对象.属性名 // Chick 重写了 Duck 的name字段,所以在取值时,自己有就先用自己的,自己没有再用继承的 // 在子类中使用父类的属性 super().属性名 ----> 对应到 Go 语言中,就是 父类名.属性名 (Duck.name) }

【12】导出结构体和字段

(1)定义包

  • nature/Animal.go
package nature type Animal struct { name string Age int // 变量名首字母大写开头,表示导出字段 ----> 可以在外部包使用 }

(2)外部导出包内部字段

package main import ( "Project1/day03/nature" "fmt" ) func main() { // 导出结构体字段 ----> 包名下 的变量首字母大写,表示导出,在其他包可以使用 // 字段名和结构体名字规则一样,大写可以导出使用,小写只能包内部使用 // Unexported field 'name' usage // 字段名首字母小写表示非导出字段,外部包不能使用 // animal := nature.Animal{name: "小梦", Age: 18} // 字段名首字母大写则表示导出字段,外部可以使用 animal := nature.Animal{Age: 18} // 不能按位置传参,只能按关键字传参 fmt.Println("这是创建的 animal :>>>> ", animal) // 这是创建的 animal :>>>> { 18} }

【13】结构体相等性

(1)可以比较

  • 如果字段都是可比较的,那结构体可以比较
package main import "fmt" func main() { // 结构体相等性 // 结构体是否能比较,取决于结构体字段 // 如果字段都是可比较的,那结构体可以比较 // 如果有不可以比较的字段,结构体就不可以比较 type Animal struct { name string age int } // 值类型 , 可以 == 比较 ; 引用类型只能 ==nil var a, b Animal = Animal{name: "梦梦", age: 18}, Animal{name: "梦梦", age: 18} fmt.Println("定义两个相同的机构体,并判断是否相等 :>>>> ", a == b) // 定义两个相同的机构体,并判断是否相等 :>>>> true }

(2)不可以比较

  • 如果有不可以比较的字段,结构体就不可以比较
package main import "fmt" func main() { // 结构体相等性 // 结构体是否能比较,取决于结构体字段 // 如果字段都是可比较的,那结构体可以比较 // 如果有不可以比较的字段,结构体就不可以比较 type Animal struct { name *string age int hobby []string // 切片类型不能比较 } var x []int = []int{1, 2, 3} var y []int = []int{1, 2, 3} // 切片类型不能 == 比较 fmt.Println("定义两个相同的机构体,并判断是否相等 :>>>> ", x == y) // Invalid operation: x == y (the operator == is not defined on []int) }
package main import "fmt" func main() { // 结构体相等性 // 结构体是否能比较,取决于结构体字段 // 如果字段都是可比较的,那结构体可以比较 // 如果有不可以比较的字段,结构体就不可以比较 type Animal struct { name *string age int hobby []string // 切片类型不能比较 } // 值类型 , 可以 == 比较 ; 引用类型只能 ==nil var a, b Animal = Animal{}, Animal{} // 初始化 // 但是不能放在一起比较 fmt.Println("定义两个相同的机构体,并判断是否相等 :>>>> ", a == b) //Invalid operation: a == b (the operator == is not defined on Animal) }

__EOF__

本文作者Chimengmeng
本文链接https://www.cnblogs.com/dream-ze/p/17827374.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Chimengmeng  阅读(42)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示