接口概念
-
接口是多个方法声明的集合
-
类型实现接口内的全部方法,就实现了该接口
-
接口的数据结构:类型、值
type iface struct {
tab *itab // 类型信息:接口类型,实际对象类型,实际对象方法地址
data unsafe.Pointer // 实际对象指针
}
-
接口限制: 不能有字段和方法、只能声明方法不能实现、可嵌入其他接口类型
-
空接口:没有声明任何方法。任何类型都可以赋值给空接口
-
var t interface{}接口变量默认值为nil -
只有当接口内部的两个指针(itab,data)都为nil时,接口才等于nil
-
接口类型断言
v, ok := t.(String) -
检查是否实现了接口
var _ fmt.Stringer = x(0)
接口使用场景
接口好处
- 解除类型依赖,屏蔽内部结构和实现细节
-
- 多态性:不同的类型相同方法名不同实现过程
-
- 解耦合:可以将抽象与实现分离,降低代码之间的耦合度,只暴露必要的方法,提高代码的可维护性和可读性
-
- 可扩展性:增加新的实现时,只需要实现接口定义的方法
使用场景
- 包对外提供访问:API设计、单元测试
- 预留扩展空间:插件系统动态加载、依赖注入
接口应用
接口检查
type x int
func (s x) String() string {
return "fmt.Stringer"
}
func init() {
// 让编译器检查,确保类型实现了指定接口
// 如果x没有实现Stringer接口,编译报错
// cannot use x(0) (constant 0 of type x) as type fmt.Stringer in variable declaration:
// x does not implement fmt.Stringer (missing String method)
var _ fmt.Stringer = x(0)
}
空接口
func interfaceEmpty() {
var i interface{}
fmt.Printf("%v type=%T, i=%v\n", i == nil, i, i)
// true type=<nil>, i=<nil>
// j不是nil接口,类型不为nil
var j interface{} = (*int)(nil)
fmt.Printf("%v type=%T, i=%v\n", j == nil, j, j)
// false type=*int, i=<nil>
i = 42
fmt.Printf("type=%T, i=%v\n", i, i)
// type=int, i=42
i = "hello"
fmt.Printf("type=%T, i=%v\n", i, i)
// type=string, i=hello
}
接口多态性
type Animal interface {
Sound() string
}
type dog struct{}
func (d dog) Sound() string {
return "Woof!"
}
type cat struct{}
func (c cat) Sound() string {
return "Meow!"
}
func interfaceMulti() {
animals := []Animal{dog{}, cat{}}
for _, animal := range animals {
fmt.Println(animal.Sound())
}
// Woof!
// Meow!
}
接口类型断言
func typeAssertions() {
var i interface{} = "hello"
s := i.(string)
fmt.Println(s) // hello
s, ok := i.(string)
fmt.Println(s, ok) // hello true
f, ok := i.(float64)
fmt.Println(f, ok) // 0 false
}
接口fmt.Stringer隐式实现
type person struct {
Name string
Age int
}
func (p person) String() string {
return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}
func fmtPersonString() {
// fmt.Println 会调用 fmt.String 接口,从而调用 person.String
a := person{"Mary", 18}
fmt.Println(a)
// Mary (18 years)
}
接口error.Error隐式实现
type mock struct {
say string
}
func (m *mock) Error() string {
return fmt.Sprintf("mock error %s", m.say)
}
// 隐式转换
func run(i int) error {
var err *mock // err的类型不为nil
if i > 1 {
err = new(mock) // err类型和值都不为nil
}
return err
// 如果要返回nil,则改写
// return nil
}
func errorTestError() {
// fmt.Println 会调用 error.Error 从而调用 mock.Error
err := run(0)
// err永远不会为nil,因为类型不为nil
if err != nil {
fmt.Printf("%T %v\n", err, err)
// *main.mock <nil>
}
err1 := run(2)
if err1 != nil {
fmt.Printf("%T %v\n", err1, err1)
// *main.mock mock error
}
}