//人
type Person struct {
name string
sex byte
age int
}
//学生
type Student struct {
Person // 匿名字段,那么默认Student就包含了Person的所有字段
id int
addr string
}
2. 初始化
//人
type Person struct {
name string
sex byte
age int
}
//学生
type Student struct {
Person // 匿名字段,那么默认Student就包含了Person的所有字段
id int
addr string
}
func main() {
//顺序初始化
s1 := Student{Person{"mike", 'm', 18}, 1, "sz"}
//s1 = {Person:{name:mike sex:109 age:18} id:1 addr:sz}
fmt.Printf("s1 = %+v\n", s1)
//s2 := Student{"mike", 'm', 18, 1, "sz"} //err
//部分成员初始化1
s3 := Student{Person: Person{"lily", 'f', 19}, id: 2}
//s3 = {Person:{name:lily sex:102 age:19} id:2 addr:}
fmt.Printf("s3 = %+v\n", s3)
//部分成员初始化2
s4 := Student{Person: Person{name: "tom"}, id: 3}
//s4 = {Person:{name:tom sex:0 age:0} id:3 addr:}
fmt.Printf("s4 = %+v\n", s4)
}
3. 成员的操作
var s1 Student //变量声明
//给成员赋值
s1.name = "mike" //等价于 s1.Person.name = "mike"
s1.sex = 'm'
s1.age = 18
s1.id = 1
s1.addr = "sz"
fmt.Println(s1) //{{mike 109 18} 1 sz}
var s2 Student //变量声明
s2.Person = Person{"lily", 'f', 19}
s2.id = 2
s2.addr = "bj"
fmt.Println(s2) //{{lily 102 19} 2 bj}
4. 同名字段
//人
type Person struct {
name string
sex byte
age int
}
//学生
type Student struct {
Person // 匿名字段,那么默认Student就包含了Person的所有字段
id int
addr string
name string //和Person中的name同名
}
func main() {
var s Student //变量声明
//给Student的name,还是给Person赋值?
s.name = "mike"
//{Person:{name: sex:0 age:0} id:0 addr: name:mike}
fmt.Printf("%+v\n", s)
//默认只会给最外层的成员赋值
//给匿名同名成员赋值,需要显示调用
s.Person.name = "yoyo"
//Person:{name:yoyo sex:0 age:0} id:0 addr: name:mike}
fmt.Printf("%+v\n", s)
}
5. 其它匿名字段
1. 非结构体类型
所有的内置类型和自定义类型都是可以作为匿名字段的
type mystr string //自定义类型
type Person struct {
name string
sex byte
age int
}
type Student struct {
Person // 匿名字段,结构体类型
int // 匿名字段,内置类型
mystr // 匿名字段,自定义类型
}
func main() {
//初始化
s1 := Student{Person{"mike", 'm', 18}, 1, "bj"}
//{Person:{name:mike sex:109 age:18} int:1 mystr:bj}
fmt.Printf("%+v\n", s1)
//成员的操作,打印结果:mike, m, 18, 1, bj
fmt.Printf("%s, %c, %d, %d, %s\n", s1.name, s1.sex, s1.age, s1.int, s1.mystr)
}
2. 结构体类型指针
type Person struct { //人
name string
sex byte
age int
}
type Student struct { //学生
*Person // 匿名字段,结构体指针类型
id int
addr string
}
func main() {
//初始化
s1 := Student{&Person{"mike", 'm', 18}, 1, "bj"}
//{Person:0xc0420023e0 id:1 addr:bj}
fmt.Printf("%+v\n", s1)
//mike, m, 18
fmt.Printf("%s, %c, %d\n", s1.name, s1.sex, s1.age)
//声明变量
var s2 Student
s2.Person = new(Person) //分配空间
s2.name = "yoyo"
s2.sex = 'f'
s2.age = 20
s2.id = 2
s2.addr = "sz"
//yoyo 102 20 2 20
fmt.Println(s2.name, s2.sex, s2.age, s2.id, s2.age)
}
二、方法
带有接收者的函数,我们称为方法(method)
本质上,一个方法则是一个和特殊类型关联的函数
⽅法总是绑定对象实例,并隐式将实例作为第⼀实参 (receiver),方法的语法如下:
func (receiver ReceiverType) funcName(parameters) (results)
参数 receiver 可任意命名。如⽅法中未曾使⽤,可省略参数名。 参数 receiver 类型可以是 T 或 *T。基类型 T 不能是接⼝或指针。 不支持重载方法,也就是说,不能定义名字相同但是不同参数的方法。在函数定义时,在其名字之前放上一个变量,即是一个方法
1. 为类型添加方法 基础类型作为接受者type MyInt int //自定义类型,给int改名为MyInt
//在函数定义时,在其名字之前放上一个变量,即是一个方法
func (a MyInt) Add(b MyInt) MyInt { //面向对象
return a + b
}
//传统方式的定义
func Add(a, b MyInt) MyInt { //面向过程
return a + b
}
func main() {
var a MyInt = 1
var b MyInt = 1
//调用func (a MyInt) Add(b MyInt)
fmt.Println("a.Add(b) = ", a.Add(b)) //a.Add(b) = 2
//调用func Add(a, b MyInt)
fmt.Println("Add(a, b) = ", Add(a, b)) //Add(a, b) = 2
结构体作为接收者
type Person struct {
name string
sex byte
age int
}
func (p Person) PrintInfo() { //给Person添加方法
fmt.Println(p.name, p.sex, p.age)
}
func main() {
p := Person{"mike", 'm', 18} //初始化
p.PrintInfo() //调用func (p Person) PrintInfo()
值语义和引用语义
方法集
类型 *T 方法集
一个指向自定义类型的值的指针,它的方法集由该类型定义的所有方法组成,无论这些方法接受的是一个值还是一个指针。
如果在指针上调用一个接受值的方法,Go语言会聪明地将该指针解引用,并将指针所指的底层值作为方法的接收者
类型 *T ⽅法集包含全部 receiver T + *T ⽅法
类型 T 方法集
一个自定义类型值的方法集则由为该类型定义的接收者类型为值类型的方法组成,但是不包含那些接收者类型为指针的方法。
但这种限制通常并不像这里所说的那样,因为如果我们只有一个值,仍然可以调用一个接收者为指针类型的方法,这可以借助于Go语言传值的地址能力实现
匿名字段
三、接口
1. 概述
在Go语言中,接口(interface)是一个自定义类型,接口类型具体描述了一系列方法的集合
2. 接口的使用
1. 定义
接⼝命名习惯以 er 结尾
接口只有方法声明,没有实现,没有数据字段
接口可以匿名嵌入其它接口,或嵌入到结构中type Humaner interface {
SayHi()
}
2. 接口实现
接口是用来定义行为的类型。
被定义的行为不由接口直接实现,而是通过方法由用户定义的类型实现
一个实现了这些方法的具体类型是这个接口类型的实例。
3. 接口组合
如果一个interface1作为interface2的一个嵌入字段,那么interface2隐式的包含了interface1里面的方法
接口转换:
超集接⼝对象可转换为⼦集接⼝,反之出错
4. 空接口:
空接口(interface{})不包含任何的方法
空接口可以存储任意类型的数值
类似于C语言的void *类型
5. 类型查询
怎么反向知道这个变量里面实际保存了的是哪个类型的对象:comma-ok断言、switch测试
1. comma-ok断言value, ok = element.(T)
value就是变量的值,ok是一个bool类型,element是interface变量,T是断言的类型 2. switch测试该笔记是本人通过学习视频,做的学习笔记~