【重学Golang】06-结构体和接口

156 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情

结构体

结构体是一种聚合类型,里面可以包含任意类型的值(结构体的成员,即字段)。

type structName struct{
    fieldName typeName
    ....
    ....
}

定义结构体,使用关键字 type 和 struct ,变量名在前,类型在后。在结构体内变量名称为成员名或字段名。在 Go 中也支持空结构体,即没有字段。

结构体类型和普通的字符串、整型一样,也可以使用同样的方式声明和初始化。如下例子,声明 person 类型的变量p,没有初始化则默认使用结构体里字段的零值。声明并初始化了变量p2,有了初始化的值就可以使用了。

type person struct{
  name string
  age p
}
​
var p person
p2 :=person{'Tom',18}
​
// 使用
fmt.Println(p2.name,p2.age)

结构体支持嵌套使用。因结构体的字段允许是任意类型,所以也包括自定义的结构体类型。如示例所示:

type person struct {
    name string
    age uint
    addr address
}
​
type address struct {
    province string
    city string
}

接口

接口是调用方的一种约定,是一种高度抽象的类型,不用和具体的实现细节绑定在一起。

type name interface {
  method1() 
  method2() string
  ......
}

定义接口,使用关键字 type 和 interface 。所以其表示自定义的类型是一个接口。接口内允许有多个方法,只是表示接口的约定,具体的方法是如何实现的,接口不关心,只有接口的实现者关心。

实现者如何实现接口?

type person struct{
  name string
  age int
}
​
type PersonAction interface {
  sayHi()
}
​
func (p person) sayHi() {
  fmt.println('hi,world')
}

接口的实现者必须是一个具体的类型,以上示例中,给结构体 person 类型定义一个方法,这个方法和接口中的方法的签名(方法名,参数,返回值)一样,这样结构体 person 就实现了PersonAction 接口。如果接口有多个方法,那必须实现接口所有的方法才算实现了接口。

在学习方法的时候说到,方法必须要有接受者,接收者可以是值接收者或者指针接收者,那么在实现接口的时候值类型和指针类型有什么区别?

先说结论:

  • 以值类型接收者实现接口的时候,不管是类型本身,还是该类型的指针类型,都实现了该接口
  • 以指针类型接收者实现接口时候,只有对应的指针类型才被认为是实现了该接口

具体证明,可以查看下面的例子:

//1、值类型接收者实现接口
func (p person) sayHi() {
  fmt.println('hi,world')
}
// 使用时
p.sayHi() // 输出 hi,world
&p.sayHi() //输出 hi,world// 2、指针类型接收者实现接口
func (p *person) sayHi() {
  fmt.println('hi,world')
}
​
// 使用
&p.sayHi() //输出 hi,world
p.sayHi() // 报错 ,因为指针类型作为接收者,只有对应指针类型实现了该接口,所以会报错