介绍
- 重要结论
- 由指针接受者实现的方法, 在赋值给接口时, 必须使用结构体指针
- 由值接收者实现的方法, 在赋值给接口时, 可以是结构体, 也可以结构体指针
- 接口的使用方式有两种:
interfaceName(&obj).func(arg)
和 interfaceInstance.func(arg)
interface
是一种类型, 抽象的类型, 区别于具体的类型
- 实现: 一个
struct
只要实现了 interface
中的全部 func
, 就是实现了这个 interface
- Go 语言提倡面向
interface
编程
- 支持
interface
嵌套
- 特点
- 优点: 非侵入式设计, 写起来更自由, 无需显式实现. 只要实现了与
interface
所包含的所有函数签名相同的方法即可
- 缺点:
duck-typing
风格并不关注 interface
的规则和含义, 也没法检查, 不能确定 struct
实现了哪些 interface
, 只能通过 goru
工具查看
使用
基本用法
package main
import "fmt"
type Sender interface {
send(string)
}
type Phone struct {
Num string
}
func (p *Phone) send(msg string) {
fmt.Printf("from %v send %v\n", p.Num, msg)
}
type Mail struct {
Addr string
}
func (m Mail) send(msg string) {
fmt.Printf("from %v send %v\n", m.Addr, msg)
}
func main() {
p1 := &Phone{Num: "111"}
p2 := Phone{Num: "222"}
m1 := Mail{Addr: "aaa"}
m2 := &Mail{Addr: "bbb"}
var iSender Sender
iSender = p1
iSender.send("xxx")
iSender = m1
iSender.send("xxx")
iSender = m2
iSender.send("xxx")
Sender(p1).send("yyy")
Sender(m1).send("yyy")
Sender(m2).send("yyy")
a := []Sender{p1, &p2, m1, m2}
for i := 0; i < len(a); i++ {
a[i].send("zzz")
}
}
类型断言
package main
import "fmt"
func main() {
x := &[]int{1, 2, 3}
var i interface{}
i = x
v, ok := i.(int)
if ok {
fmt.Printf("断言成功, %T, %v", v, v)
} else {
fmt.Printf("断言失败, %T, %v", v, v)
}
switch v := i.(type) {
case int:
case string:
default:
}
}
补充知识
空接口
- 没有实现 任何func 的接口, 就是空接口
- 任何类型都实现了空接口, 空接口可以接收任意类型的值
package main
import "fmt"
func main() {
var i interface{}
i = 10
fmt.Printf("%T, %[1]v, %T\n", i, &i)
i = "10"
fmt.Printf("%T, %[1]v, %T\n", i, &i)
i = [1]int{10}
fmt.Printf("%T, %[1]v, %T\n", i, &i)
i = []int{10}
fmt.Printf("%T, %[1]v, %T\n", i, &i)
i = t{}
fmt.Printf("%T, %[1]v, %T\n", i, &i)
}
结构体方法实现接口的区别
- 实现方法尽量使用指针作为接收者
structFunc
是值接收者时, interface
能使用指针和值
structFunc
是指针接收者时, interface
只能使用指针
- 以上两种情况都存在时, 只能使用指针
底层实现