interface接口应用

75 阅读2分钟

接口概念

  • 接口是多个方法声明的集合

  • 类型实现接口内的全部方法,就实现了该接口

  • 接口的数据结构:类型、值

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)

接口使用场景

接口好处

  • 解除类型依赖,屏蔽内部结构和实现细节
    1. 多态性:不同的类型相同方法名不同实现过程
    1. 解耦合:可以将抽象与实现分离,降低代码之间的耦合度,只暴露必要的方法,提高代码的可维护性和可读性
    1. 可扩展性:增加新的实现时,只需要实现接口定义的方法

使用场景

  • 包对外提供访问: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
	}
}