how-to-use-gointerface.md

Go 如何使用接口

  • 常见的写法,经常看到很多人的写法是这样的:
1
2
3
4
5
6
7
8
9
package animals

type Animal interface {
Speak() string
}

//实现animal这个接口
type Dog struct{}
func (a Dog) Speak() string { return "woof" }
1
2
3
4
5
package circus

import "animals"

func Perform(a animal.Animal) string { return a.Speak() }
  • 这种写法很像 java 风格,java-style接口使用方式了,解读上面的代码:
    • 定义了一个 Animal 的接口
    • 定义了一个 Dog 的结构体
    • Dog 的结构体有一个方法为 Speak,这样 Dog 这个结构体实现了 Animal 这个接口
  • 以上写法可以概括为“编写类型以实现接口”。
  • 很明显它只有一种类型可以实现接口而没有明显的扩展方式。
  • 参数通常采用具体类型而不是接口类型。

更建议的写法

  • Go 的接口,不是编写类型来实现接口,而是编写接口满足需求。就拿上面的代码为例,不是在 animals 中定义 Animal,而是在使用的位置来定义接口。
1
2
3
4
5
6
7
8
9
10
11
package animals

type Dog struct{}
func (a Dog) Speaks() string { return "woof" }
package circus

type Speaker interface {
Speak() string
}

func Perform(a Speaker) string { return a.Speak() }
  • 定义类型
  • 在使用的位置定义接口
  • 这种是方式减少了包 animals 对组件的依赖。减少依赖可以有助于构建一个更强壮的程序。

Postel 定律

  • 编写优秀软件的好准则之一 Postel 定律。这个翻译有很多版本不同的环境都有不同的理解。贴原文

“Be conservative with what you do, be liberal with you accept”

在 Go 中的理解

接收接口,返回结构(Accept interfaces,return structs)

  • Go 的谚语中,Rob pike 说过这样一句话

“the empty interface says nothing“ - Rob Pike

  • 写 go 更多应该按照的 go 的思想 和行为来编写代码。而不是保持过多原有的思想。