接口(interface)
定义一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节。
在go语言中,接口(interface)是一种抽象的类型。
interface
是一组method
的集合,是duck-type programming
的一种体现,不关心属性(数据),只关心行为(方法)。
Go语言提倡面向接口编程。
定义接口如下:
type 接口类型名 interface {
方法名1(参数列表1) 返回值列表1
方法名2(参数列表2) 返回值列表2
}
其中,
- 接口名:Go语言中的接口命名时候,一般会再单次后面添加
er
,例如写文件的接口叫Writer
。
type animal interface {
eat() string
}
一个对象只要全部实现了接口中的方法,那么就实现了这个接口。
package main
import (
"fmt"
)
type Cat struct {}
func (c *Cat)Eat() string { return "吃鱼" }
type Dog struct {}
func (d *Dog)Eat() string { return "吃骨头"}
type Animal interface {
Eat() string
}
func main(){
var a []Animal
c := Cat{}
d := Dog{}
// fmt.Println(c.Eat())
// fmt.Println(d.Eat())
a = append(a, &c)
a = append(a, &d)
for _, value := range a {
fmt.Println(value.Eat())
}
}
一个类型可以实现多个接口。
package main
import (
"fmt"
)
type Eater interface {
Eat() string
}
type Mover interface {
Move() string
}
type Cat struct { name string}
func (c *Cat)Eat() string { return c.name + "吃鱼" }
func (c *Cat)Move() string { return c.name + "猫走" }
func main(){
c := Cat{name: "Tom"}
fmt.Println(c.Eat())
fmt.Println(c.Move())
}
多个类型实现同一个接口。
并且一个接口的方法,不一定由一个类型全部实现,接口的方法可以通过类型中嵌入其它类型或者结构体实现。
package main
import (
"fmt"
)
type Tester interface {
Eat() string
Move() string
}
type Animal struct {
name string
}
type Cat struct {
age int
a Animal
}
func (c *Cat)Eat() string { return "吃鱼" }
func (a *Animal)Move() string { return "猫走" }
func main(){
c := Cat{
age: 6,
a: Animal{
name: "Tom",
},
}
fmt.Println(c.Eat())
fmt.Println(c.a.Move())
}
接口嵌套
package main
import (
"fmt"
)
type Eater interface {
Eat() string
}
type Mover interface {
Move() string
}
type Animal interface {
Eater
Mover
}
type Cat struct {}
func (c *Cat)Eat() string { return "吃鱼" }
func (c *Cat)Move() string { return "猫走" }
type Dog struct {}
func (d *Dog)Eat() string { return "吃骨头"}
func (d *Dog)Move() string { return "狗走" }
func main(){
var a []Animal
c := Cat{}
d := Dog{}
a = append(a, &c)
a = append(a, &d)
for _, value := range a {
fmt.Println(value.Eat())
fmt.Println(value.Move())
}
}
空接口
没有定义任何方法的接口,因此任何类型都实现了空接口。
空接口类型的变量可以存储任意类型的变量。
主要作用是:
- 空接口作为参数或者返回值,可接受任何类型
- 使用空接口可以实现任意值的字典
package main
import (
"fmt"
)
//空接口作为参数,可接受任何类型
func showType(a interface{}){
fmt.Printf("%T\n", a)
}
func main(){
//空接口可用这种方式定义
var x interface{}
x = 100
fmt.Println(x)
showType(x)
x = "哈哈"
fmt.Println(x)
showType(x)
x = false
fmt.Println(x)
showType(x)
x = struct{ name string}{ name: "张三" }
fmt.Println(x)
showType(x)
//使用空接口可以实现任意值的字典
m := make(map[string]interface{}, 10)
m["a"] = 1
m["b"] = "b"
m["c"] = true
m["d"] = 12.23
fmt.Println(m)
}
输出结果是
100
int
哈哈
string
false
bool
{张三}
struct { name string }
map[a:1 b:b c:true d:12.23]
类型断言
空接口可以存储任意类型的值,则如何获取其存储的具体数据呢?
采用格式是x.(T)
,返回值是两个:第二是bool类型,true断言成功,false断言失败;第一值是,如果断言正确返回值,否则返回断言类型的默认值。
- x:类型为interface{}的变量
- T:表示断言x可能是的类型
package main
import (
"fmt"
)
func main(){
//空接口
var x interface{}
x = 100
//类型断言
v1, ok := x.(int)
fmt.Println(ok)
fmt.Println(v1)
v2, ok := x.(bool)
fmt.Println(ok)
fmt.Println(v2)
x = "哈哈"
//类型断言
v3, ok := x.(string)
fmt.Println(ok)
fmt.Println(v3)
v4, ok := x.(int)
fmt.Println(ok)
fmt.Println(v4)
}
输出结果是:
true
100
false
false
true
哈哈
false
0
值接收者和指针接收者区别
值接收者的话,值接收者和指针接收者都可以用
指针接收者的话,只能指针接收者可以用
package main
import (
"fmt"
)
type Mover interface {
Move() string
}
type Cat struct {
name string
}
//值接收者
func (c Cat)Move() string { return c.name + "吃鱼" }
//指针接收者
// func (c *Cat)Move() string { return c.name + "吃鱼" }
func main(){
//方法采用值接收者时候,值和指针传参都可以
var m Mover
c := Cat{name: "Tom"}
m = c
fmt.Println(m)
fmt.Println(m.Move())
s := &Cat{name: "Jerry"}
m = s
fmt.Println(m)
fmt.Println(m.Move())
//方法采用指针接收者时候,只能是指针传参
// var m Mover
// c := &Cat{name: "Tom"}
// m = c
// fmt.Println(m)
// fmt.Println(m.Move())
}