interface
interface 类型定义了一组方法,如果某个对象实现了某个接口的所有方法(实现 interface 中的一个 method 即函数名,形参类型,个数,顺序,返回参数类型,个数,顺序对应),则此对象就实现了此接口。interface 可以被任意的对象实现。一个对象可以实现任意多个 interface
类似于 struct 继承匿名字段的 method,如果一个 interface1 作为 interface2 的一个嵌入字段,那么 interface2 隐式的包含了 interface1 里面的 method
interface 的声明及实现
package main
import (
"fmt"
)
type Human struct {
name string
age int
phone string
}
type Student struct {
Human //匿名字段
school string
loan float32
}
type Employee struct {
Human //匿名字段
company string
money float32
}
//定义 interface
type Men interface {
SayHi()
Sing(lyrics string)
Guzzle(beerStein string)
}
type YoungChao interface {
SayHi()
Sing(song string)
BorrowMoney(amount float32)
}
type ElderlyGent interface {
SayHi()
Sing(song string)
SpendSalary(amount float32)
}
//Human 对象实现 Sayhi 方法
func (h *Human) SayHi() {
fmt.Println("hi, i am a Human")
}
//Human 对象实现 Sing 方法
func (h *Human) Sing(lyrics string) {
//形参的名字没有任何影响, 虽然三个 interface 中的 Sing mehod 形参名字不同, 但是他们的类型相同
//所以 Human 实现了一个 Sing 等于三个 interface 的 Sing method 都实现了
fmt.Println("lalalala")
}
//Human 对象实现 Guzzle 方法
func (h *Human) Guzzle(beerStein string) {
fmt.Println("Guzzle")
}
func (h *Human) BorrowMoney(amount float32) {
fmt.Println("BorrowMoney")
}
//Student 覆盖继承自 Human 中的 SayHi method
func (s *Student) SayHi() {
fmt.Println("hi, i am a student")
}
func main() {
var cnt Men
var gel YoungChao
//如果我们定义了一个interface的变量,那么这个变量里面可以存实现这个interface的任意类型的对象
cnt = new(Human)
gel = new(Human)
cnt.SayHi() //hi, i am a Human
gel.Sing("xxx") //lalalala
//Student 含有匿名字段 Human, 所以能继承 Human 中的 method, 即 Human 实现了的 interface 在 Student 中也能用
cnt = new(Student)
//Student 中覆盖了继承自 Human 中的 SayHi method
cnt.SayHi() //hi, i am a student
}
注意
若多个 interface 中包含同一个 method(即方法名,形参,返回参数全部一致),则某个类型实现该 method 一次即等于实现了所有 interface 中的该方法
匿名字段的 method 可以继承,命名字段不可。即类型 x 包含了匿名字段 y,则 y 实现的方法 x 也具有。若 x 包含了命名字段 y,则 y 中的 method 不能直接被 x 类型对象调用,只能由 x 对象中的 y 类型对象间接调用
继承自匿名字段的 method 可以被覆盖
如果我们定义了一个 interface 的变量,那么这个变量里面可以存实现这个 interface 的任意类型的对象。由这些特性可知,go 可以实现类似于 c++ 中的多态
空 interface
空 interface (interface{}) 不包含任何的 method,正因为如此,所有的类型都实现了空 interface。因此它可以存储任意类型的对象
package main
import (
"fmt"
)
func main() {
var a interface{}
var i int = 5
s := "hello"
a = i
fmt.Println(a) //5
a = s
fmt.Println(s) //hello
}
interface 变量存储的类型
由前面的内容可知 interface 类型的变量可以存储任意实现了该 interface method 集合的对象,那么如何判断一个 interface 变量中的对象类型是什么呢?
Comma-ok 断言
value, ok = element.(T),这里的 value 就是变量的值,ok 是一个 bool 类型,T 是断言的类型。如果 element 里面确实存储了 T 类型的数值,那么 ok 返回 true,否则返回 false。
package main
import (
"fmt"
"strconv"
)
type Element interface{}
type List []Element
type Person struct {
name string
age int
}
func (p Person) String() string {
return "[name:" + p.name + " age:" + strconv.Itoa(p.age) + "]"
}
func main() {
list := make(List, 3)
list[0] = 1
list[1] = "hello"
list[2] = Person{"Dennis", 70}
for index, element := range list {
if value, ok := element.(int); ok {
fmt.Println("index:", index, "value:", value, "type:int")
} else if value, ok := element.(string); ok {
fmt.Println("index:", index, "value:", value, "type:sting")
} else if value, ok := element.(Person); ok {
fmt.Println("index:", index, "value:", value, "type:Person")
}
}
}
//index: 0 value: 1 type:int
//index: 1 value: hello type:sting
//index: 2 value: [name:Dennis age:70] type:Person
switch测试
package main
import (
"fmt"
"strconv"
)
type Element interface{}
type List []Element
type Person struct {
name string
age int
}
func (p Person) String() string {
return "[name:" + p.name + " age:" + strconv.Itoa(p.age) + "]"
}
func main() {
list := make(List, 3)
list[0] = 1
list[1] = "hello"
list[2] = Person{"Dennis", 70}
for index, element := range list {
switch value := element.(type) {
case int:
fmt.Println("index:", index, "value:", value, "type:int")
case string:
fmt.Println("index:", index, "value:", value, "type:string")
case Person:
fmt.Println("index:", index, "value:", value, "type:Person")
}
}
}
//index: 0 value: 1 type:int
//index: 1 value: hello type:sting
//index: 2 value: [name:Dennis age:70] type:Person