结构体 struct
用来自定义复杂数据结构
struct 里面可以包含多个字段(属性)
struct类型可以定义方法,注意和函数的区别
struct类型是值类型
struct类型可以嵌套
GO语言没有class类型,只有struct 类型
声明:
12345678910111213141516type 标识符 struct{field1 typefield2 type}//例type Student struct{Name stringAge intScore int}var stu Studentstu.Name = "tony"stu.Age = 18定义的三种方式
123var stu Studentvar stu *Student = new(Student) //指针var stu *Student = &Student{} //指针- 指针访问元素时,用(*stu).Age 或者 直接 stu.Age 也可以,GO做了优化
struct的内存布局,所有字段在内存是连续的
golang中struct没有构造函数,一般可以使用工厂模式来解决
12345678910111213141516Package modeltype student struct{Name stringAge int}func NewStudent(name string, age int) *student{return &student{Name:name,Age:age,}}Package mainS := new(student)S := model.NewStudent("dante",18)再次强调
- make用来创建map,slice,channel
- new 用来创建值类型
- struct是值类型
匿名字段
1234567891011121314151617type Cart struct {name stringage int}type Train struct {Cartint}func main() {var t Traint.name = "train"t.age = 100t.int = 666fmt.Println(t)}- 如果匿名字段是结构体,可以简化结构体多层调用
- 如果有冲突就不能用简化的了,还得指定具体子结构体
- t.Cart1.name = “xxx”
- t.Cart2.name = “222”
- 如果有冲突就不能用简化的了,还得指定具体子结构体
- 如果匿名字段是普通值类型,那么就直接把值类型作为成员调用
- 但是这都是在没有冲突下使用,如果有冲突,就不能这么用了
- 如果匿名字段是结构体,可以简化结构体多层调用
GO中继承通过匿名字段来完成
struct的tag机制
tag 是放在结构体中元素后面的字符串
我们可以为struct中的每个字段,写上一个tag。这个tag可以通过反射的机制获取到,最常用的场景就是json序列化和反序列化。
背景
- 如果结构体里面的字段首字母是小写,作为另一个包中的json序列化函数就无法访问这些小写的结构体,无法进行序列化
- 虽然可以通过将结构体中的成员首字母大写来解决,但是在有时候和对方通信,协议中大家约定是小写字母,此时该怎么办呢?
- 这时候就用到tag
解决方案
12345type Student struct {Name string `json:"student_name"`Age int `json:"age"`Score int `json:"score"`}- 这样json包能通过反射获取到tag内容,并序列化时按tag中的内容进行
结构体的方法
- GO中的方法是作用在特定类型的变量上,因此自定义类型,都可以有方法,而不仅仅是struct
定义
func (recevier type) methodName(参数列表)(返回值列表){}
例:
123456789101112131415161718192021222324252627282930313233343536373839404142type integer intfunc (p integer) print() {fmt.Println("p is ", p)}func (p *integer) set(b integer) {*p = b}type Student struct {Name stringAge intScore intsex int}func (p *Student) init(name string, age int, score int) {p.Name = namep.Age = agep.Score = scorefmt.Println(p)}func (p Student) get() Student {return p}func main() {var stu Studentstu.init("stu", 10, 200)stu1 := stu.get()fmt.Println(stu1)var a integera = 100a.print()a.set(1000)a.print()}使用匿名字段实现继承,同样也能继承方法
1234567891011121314151617181920212223242526272829303132333435package mainimport "fmt"type Car struct {weight intname string}func (p *Car) Run() {fmt.Println("running")}type Bike struct {Carlunzi int}type Train struct {c Car}func main() {var a Bikea.weight = 100a.name = "bike"a.lunzi = 2fmt.Println(a)a.Run()var b Trainb.c.weight = 100b.c.name = "train"b.c.Run()}多重继承也是使用匿名字段实现
- 如果各子结构体内有字段冲突就不能使用简化指定方法,要具体到子结构体名称去调用。
如果结构体的实现了某些接口的方法,就等于实现了这个接口
- 就可以获得这个接口的特性
- 例如:结构体实现一个格式化打印接口的方法
12345678910111213141516171819202122232425package mainimport "fmt"type Car struct {weight intname string}type Train struct {Car}func (p Train) String() string {str := fmt.Sprintf("name=[%s] weight=[%d]", p.name, p.weight)return str}func main() {var b Trainb.weight = 100b.name = "train"fmt.Printf("%s", b)}