Go通关06:struct和interface,结构体和接口的使用

结构体

定义

结构体是种聚合类型,里面可以包含任意类型的值,这些值就是结构体的成员,或成为字段,定义结构体,需要使用 type+struct 关键字组合

type person struct { //人结构体
  name string //人的名字
  age uint //人的年龄
}
  1. type 与 struct 是关键字,用来定义一个新结构体的类型。
  2. person 为结构体名字。
  3. name/age 为结构体的字段名,后面指对应的字段类型。
  • 字段声明和变量类似,变量名在前,类型在后
  • 字段可以是人一个,一个字段都没有的结构体,成为空结构体。
  • 结构体也是一种类型,比如 person 结构体和 person 类型是一个意思。

声明

  1. 像普通字符串、整型医院声明初始化
    var p person

声明了一个person类型的变量p,但是没有初始化,所以默认使用结构体里字段的零值。

  1. 字面量方式初始化
    p := person{"无尘",18}

表示结构体变量 p 的name字段初始化为“无尘”,age字段初始化为18。顺序必须和字段定义顺序一致。

  1. 根据字段名称初始化
    p := person{age:18,name:"无尘"}

像这样指出字段名,就可以打乱初始化字段的顺序。也可以只初始化其中部分字段,剩余字段默认使用零值: p := person{age:30}

字段结构体

结构体字段可以是任意类型,包括自定义的结构体类型:

type person struct { //人结构体
  name string
  age uint
  addr address //使用自定义结构体类型
}
type address struct { //地址结构体
  city string
}

对于这样嵌套结构体,初始化和一般结构体类似,根据字段对应的类型初始化即可:

p := person {
  age:18,
  name:"无尘",
  addr:address{
    city:"北京",
  },
}

结构体的字段和调用一个类型的方法一样,都是使用点操作符“.”:

fmt.Println(p.age)
//访问嵌套结构体里的city字段的值:
fmt.Println(p.addr.city) 

接口

定义

接口是一个抽象的类型,是和调用方的一种约定。接口只需要定义约定,告诉掉用方可以做什么,而不用知道它的内部实现。
接口的定义是 type + interface关键字类实现。

//Info 是一个接口,它有方法 Getinfo()string
type Info interface {
  Getinfo() string
}

对应 Stringer 接口,它会告诉调用者可以通过 String()放获取一个字符串,这就是接口的约定,而这个字符串是怎么获取到的,接口并不关心,调用者也不用关心,因为这些是接口的实现者来处理的。

接口的实现

接口的实现者必须是一个具体的类型:

func (p person) Getinfo() string {
  return fmt.Sprintf("my name is %s,age is %d",p.name,p.age)
} 
  • 给结构体类型 person 定义了一个方法,这个方法和接口里的方法名称、参数、返回值都一样,就表示这个结构体 person 实现了 Info 接口。
  • 如果一个接口有多个方法,那么要实现接口中的所有方法才算是实现了这个接口。

使用

我们先定义一个可以打印 Info 接口的函数:

func printInfo(i Info) {
  fmt.Println(i.Getinfo())
}
  • 定义函数 pringInfo,它接收一个 Info 接口类型的参数,然后打印接口 Getinfo 方法返回的字符串。
  • 这个 pringInfo 函数此处是面向接口编程,只有任何一个类型实现了Info接口,都可以使用这个函数打印出对应的字符串,而不用关心具体的类型实现。
printInfo(p) 
//结果为:my name is 无尘,age is 18

因为 person 类型实现了Info接口,所以变量p可以作为函数printInfo的参数。

值接受者、指针接受者

  1. 实现一个接口,必须实现接口中所有的方法。
  2. 定义一个方法,有值类型接收者和指针类型接收者,两者都可以调用方法,因为Go编译器自动做了转换。
  3. 但是接口的实现,值类型接收者和指针类型接收者不一样

上面接口体person实现了Info接口,是否结构体指针也实现了该接口呢?

printInfo(&p)

测试发现p的指针作为参数函数也是可以正常运行,表明以值类型接收者实现接口,类型本身和该类型的指针类型,都实现了该接口

那么把接收者改成指针类型:

func (p *person) Getinfo() string {
	return fmt.Sprintf("my name is %s,age is %d",p.name,p.age)
}

然后再调用函数 printInfo(p),代码编译不通过,表明以指针类型接收者实现接口,只有对应的指针类型才被认为实现了接口

方法接收者 实现接口类型
(p person) person和*person
(p *person) *person
  • 当值类型作为接收者,person类型和*person类型都实现了该接口。
  • 当指针类型作为接收者,只有 *person类型实现了该接口。

Go通关06:struct和interface,结构体和接口的使用

上一篇:delphi处理消息的几种方式


下一篇:XDOC云服务API(二)