结构体
Go语言中的结构体几乎和C语言中的结构体一模一样
都需要先定义结构体类型, 再定义结构体变量
都是用来保存一组不同类型数据的C语言定义结构体类型的格式
struct 结构体类型名称{
属性名称 属性类型;
属性名称 属性类型;
}
- Go语言定义结构体类型的格式
type 结构体类型名称 struct{
属性名称 属性类型;
属性名称 属性类型;
}
//定义一个结构体类型
type Person struct{
name string
age int
}
- C语言中通过结构体类型定义结构体变量, 必须拷贝struct
struct 结构体类型名称 结构体变量名称; - Go语言中通过结构体类型定义结构体变量, 不用拷贝struct
var 结构体变量名称 结构体类型名称
//通过结构体类型定义结构变量
var per Person
per.name = "luo"
per.age = 18
fmt.Println(per)
- 和C语言中的结构体一样, 可以定义结构体变量的同时初始化, 也可以先定义结构体变量再初始化
type Person struct{
name string
age int
}
// 定义的同时初始化
var per Person = Person{"luo", 18}
fmt.Println(per)
// 先定义再初始化
var per2 Person
//per = Person{"luo", 18} // 完全初始化
per2 = Person{name:"luo"} // 部分初始化, 必须通过属性名称指定要给谁初始化
fmt.Println(per2)
- 注意点:
和切片以及字典不一样, 结构体变量定义之后就可以直接使用了
(若结构体中有slice map不能直接使用,见后文)
结构体和函数
- 结构体类型和数组类型一样, 在Go语言中都是值传递,修改形参不会影响到实参
package main
import "fmt"
// 1.定义一个结构体类型
type Person struct {
name string
age int
}
func main() {
// 2.定义一个结构体变量
p1 := Person{"luo", 18}
// 3.再定义一个结构体变量
var p2 Person
// 4.将p1赋值给p2
p2 = p1
// 5.修改p2的值
fmt.Println(p1) //{luo 18}
p2.name = "zs"
fmt.Println(p1) //{luo 18}
fmt.Println(p2) //{zs 18}
change(p1)
fmt.Println(p1) //{luo 18}
}
func change(pp Person) {
pp.name = "zs"
}
复杂结构体
- 注意点: 如果结构体的属性是切片和字典类型, 那么就不能直接操作,必须先给切片初始化(创建切片)
package main
import (
"fmt"
)
func main() {
type Person struct {
age int
score float32
name string
arr [3]int
sce []int
dict map[string]string
}
var per Person
// 常规的数据类型, 我们都可以直接操作, 完全没有问题
per.age = 18
per.score = 100
per.name = "luo"
per.arr[0] = 1
per.arr[1] = 3
per.arr[2] = 5
fmt.Println(per) //{18 100 luo [1 3 5] [] map[]}
// 注意点: 如果结构体的属性是切片和字典类型, 那么就不能直接操作
// 必须先给切片初始化(创建切片)
per.sce = make([]int, 2)
per.sce[0] = 123
per.sce[1] = 456
//per.sce[2] = 789 // 通过索引操作切片, 不能超出切片的长度
fmt.Println(per) //{18 100 luo [1 3 5] [123 456] map[]}
per.dict = make(map[string]string)
per.dict["name"] = "zs"
fmt.Println(per) //{18 100 luo [1 3 5] [123 456] map[name:zs]}
//demo
type LUO struct {
name string
age int
score float64
arr [3]int
sce []int
dict0 map[string]string
}
var luo LUO
luo.name="lyw"
luo.age = 0
luo.score = 99.5
luo.arr[0] = 1
luo.arr[1] = 2
luo.arr[2] = 3
luo.sce = make([]int,2)
luo.sce[0] = 111
luo.sce[1] = 222
luo.dict0 = make(map[string]string)
luo.dict0["dog"] = "zjw"
fmt.Println(luo) //{lyw 0 99.5 [1 2 3] [111 222] map[dog:zjw]}
}
结构体之间的转换
- 结构体变量之间可以相互转换, 但是必须保证结构体类型的
属性名称 属性类型 属性顺序 属性的个数 都一样
package main
import "fmt"
func main() {
type Person1 struct {
name string
age int
}
// 属性顺序不同
type Person2 struct {
age int
name string
}
// 如果属性名称和类型都一样, 但是顺序不一样, 不能转换
//var p1 Person1 = Person1{}
//var p2 Person2
//p2 = Person2(p1)
//fmt.Println(p1)
//fmt.Println(p2)
type Person3 struct {
name1 string
age int
}
// 如果属性的类型和顺序都一样, 但是名称不一样, 不能转换
//var p1 Person1 = Person1{}
//var p2 Person3
//p2 = Person3(p1)
//fmt.Println(p1)
//fmt.Println(p2)
type Person4 struct {
name string
age int
score int
}
// 如果属性的名称和类型都一样, 但是个数不一样, 不能转换
//var p1 Person1 = Person1{}
//var p2 Person4
//p2 = Person4(p1)
//fmt.Println(p1)
//fmt.Println(p2)
type Person5 struct {
name [10]byte
age int
}
// 如果属性名称和个数都一样, 但是属性数据类型不一样, 不能转换
//var p1 Person1 = Person1{}
//var p2 Person5
//p2 = Person5(p1)
//fmt.Println(p1)
//fmt.Println(p2)
type Person6 struct {
name string
age int
}
// 只有属性个数, 属性名称, 属性类型, 属性顺序都一样, 才能转换
var p1 Person1 = Person1{"luo",18}
var p2 Person6
p2 = Person6(p1)
fmt.Println(p1) //{luo 18}
fmt.Println(p2) //{luo 18}
}
结构体匿名属性
- 什么是匿名结构体属性?
只有数据类型,没有名称的属性就是匿名属性
type Person struct {
int // 只有数据类型, 没有名称, 就是匿名属性
name string
}
- 如何操作匿名属性?
匿名属性的数据类型就是匿名属性的名称, 所以可以通过匿名属性的数据类型来操作
type Person struct {
int
string
}
var per Person
per.int = 18
per.string = "luo"
fmt.Println(per)
- 匿名属性一般都用于结构体的嵌套定义
结构体的属性又是一个结构体
type Date struct {
year int
month int
day int
}
type Person struct {
name string
Date
}
/*
type Animal struct {
name string
Date
}
*/
var per Person = Person{"zs", Date{2012, 12, 12}}
fmt.Println(per) // {zs {2012 12 12}}
var per2 Person = Person{"lyw",Date{2018,9,28}}
fmt.Println(per2)
嵌套定义结构体方式
- 第一种方式
type 结构体名称1 struct{
}
type 结构体名称2 struct{
结构体名称1
}
第一种方式: 没有重名属性的情况
type Person struct {
name string
age int
}
type Student struct {
Person
score float32
}
stu := Student{Person{"zs", 18}, 99.5}
fmt.Println(stu)
// 结构体嵌套定义时, 如何操作结构体的属性
//第一种访问方式
//fmt.Println(stu.Person.name)
//fmt.Println(stu.Person.age)
//fmt.Println(stu.score)
// 第二种访问的方式
// 会先去Student结构体中查询有没有name属性, 如果有就直接访问
// 如果没有会继续查找嵌套的匿名结构体中有没有, 如果有就访问匿名结构体中的name属性
fmt.Println(stu.name)
fmt.Println(stu.age)
fmt.Println(stu.score)
第一种方式: 有重名属性的情况
type Person struct {
name string
age int
}
type Teacher struct {
Person
name string
title string
}
tea := Teacher{Person{"luo", 18}, "zs", "老师"}
fmt.Println(tea) //{{luo 18} zs 老师}
fmt.Println(tea.name) // zs 有同名属性会采取就近原则,不会向上查找
fmt.Println(tea.Person.name) // luo
- 第二种方式
type 结构体名称1 struct{
}
type 结构体名称2 struct{
结构体名称1
}
type 结构体名称3 struct{
结构体名称2
}
第二种方式: 没有重名属性的情况
type Object struct {
name string
}
type Person struct {
Object
age int
}
type Student struct {
Person
score float32
}
stu := Student{Person{Object{"zs"}, 18}, 99.5}
fmt.Println(stu) // {{{zs} 18} 99.5}
fmt.Println(stu.score)//99.5
fmt.Println(stu.Person.age)//18
fmt.Println(stu.age) //18
fmt.Println(stu.Person.Object.name) //zs
fmt.Println(stu.Person.name) //zs
fmt.Println(stu.name) //zs 会往上查找
第二种方式: 有重名属性的情况
type Object struct {
name string
}
type Person struct {
Object
name string
age int
}
type Student struct {
Person
name string
score float32
}
stu2 := Student{Person{Object{"lyw"},"zjw",8},"dog",0.1}
fmt.Println(stu2) //{{{lyw} zjw 8} dog 0.1}
fmt.Println(stu2.name) // dog
fmt.Println(stu2.Person.name) // zjw
fmt.Println(stu2.Person.Object.name) // lyw
- 第三种方式
type 结构体名称1 struct{
}
type 结构体名称2 struct{
}
type 结构体名称3 struct{
结构体名称1
结构体名称2
}
第三种方式: 没有重名属性的情况
type Object struct {
name string
}
type Person struct {
age int
}
type Student struct {
Object
Person
score float32
}
stu := Student{Object{"luo"}, Person{18}, 99.5}
fmt.Println(stu) //{{luo} {18} 99.5}
fmt.Println(stu.Object.name) //luo
fmt.Println(stu.name) //luo
fmt.Println(stu.Person.age) //18
fmt.Println(stu.age) //18
第三种方式: 有重名属性的情况
type Object struct {
name string
}
type Person struct {
name string
}
type Student struct {
Object
Person
name string
score float32
}
stu := Student{Object{"zs"}, Person{"ls"}, "luo",99.5}
fmt.Println(stu.name) //luo
fmt.Println(stu.Object.name) //zs
fmt.Println(stu.Person.name) //ls
结构体的嵌套定义的注意点:
- 只有匿名结构体才支持向上查找
type Person struct {
name string
}
type Student struct {
//Person // 匿名属性
per Person // 命名属性
age int
}
stu := Student{Person{"lnj"}, 18}
//fmt.Println(stu.per.name)
fmt.Println(stu.name) //非匿名属性不会向上查找,会报错
- 结构体的属性类型不能是当前结构体的类型,如果匿名属性是一个结构体类型, 那么这个结构体类型不能是自己
type Person struct {
Person // 错误
name string
}
type Student struct {
*Student // 正确, 链表
age int
}
有疑问加站长微信联系(非本文作者)