Golang 接口 : ~~~ 接口是一个或多个方法签名的集合。 任何类型的方法集中只要拥有该接口'对应的全部方法'签名。 就表示它 "实现" 了该接口,无须在该类型上显式声明实现了哪个接口。 这称为Structural Typing。 所谓对应方法,是指有相同名称、参数列表 (不包括参数名) 以及返回值。 当然,该类型还可以有其他方法。 接口只有方法声明,没有实现,没有数据字段。 接口可以匿名嵌入其他接口,或嵌入到结构中。 对象赋值给接口时,会发生拷贝,而接口内部存储的是指向这个复制品的指针,既无法修改复制品的状态,也无法获取指针。 只有当接口存储的类型和对象都为nil时,接口才等于nil。 接口调用不会做receiver的自动转换。 接口同样支持匿名字段方法。 接口也可实现类似OOP中的多态。 空接口可以作为任何类型数据的容器。 一个类型可实现多个接口。 接口命名习惯以 er 结尾。 ~~~ Go 语言中的接口很特别,而且提供了难以置信的一系列灵活性和抽象性。它们指定一个特定类型的值和指针表现为特定的方式。从语言角度看,接口是一种类型,它指定一个方法集,所有方法为接口类型就被认为是该接口。 interface类型可以定义一组方法,但是这些不需要实现。并且interface不能包含任何变量。 interface类型默认是一个指针 interface语法: ~~~ type example interface{ Method1(参数列表) 返回值列表 Method2(参数列表) 返回值列表 … } var a example a.Method1() ~~~ 下面定义一个接口: ~~~ type Notifier interface { Notify() error } ~~~ 我们定义了一个叫做 Notifier 的接口并包含一个 Notify 方法。当一个接口只包含一个方法时,按照 Go 语言的约定命名该接口时添加 -er 后缀。这个约定很有用,特别是接口和方法具有相同名字和意义的时候。 我们可以在接口中定义尽可能多的方法,不过在 Go 语言标准库中,你很难找到一个接口包含两个以上的方法。 实现接口 Golang中的接口,不需要显示的实现。只要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口。因此,golang中没有implement类似的关键字。 ~~~ package main import ( "fmt" ) type I interface { Method1() int Method2() string } type S struct { name string age int } func (s S) Method1() int { return s.age } func (s S) Method2() string { return s.name } func main() { var user I = S{"Murphy", 28} age := user.Method1() name := user.Method2() fmt.Println(age, name) } ~~~ 输出结果: ~~~ 28 Murphy ~~~ 如果一个变量含有了多个interface类型的方法,那么这个变量就实现了多个接口。 ~~~ package main import ( "fmt" ) type I1 interface { Method1() int } type I2 interface { Method2() string } type S struct { name string age int } func (s S) Method1() int { return s.age } func (s S) Method2() string { return s.name } func main() { user := S{"Murphy", 28} age := user.Method1() name := user.Method2() fmt.Println(age, name) } ~~~ 输出结果: ~~~ 28 Murphy ~~~ 如果一个变量只含有了1个interface的部分方法,那么这个变量没有实现这个接口。 ~~~ package main import ( "fmt" ) type I interface { Method1() int Method2() string } type S struct { name string age int } func (s S) Method1() int { return s.age } // func (s S) Method2() string { // return s.name // } func main() { var user I = S{"Murphy", 28} age := user.Method1() // name := user.Method2() // fmt.Println(age, name) fmt.Println(age) } ~~~ 输出结果: ~~~ ./main.go:26:6: cannot use S literal (type S) as type I in assignment: S does not implement I (missing Method2 method) ~~~ 当涉及到我们该怎么让我们的类型实现接口时,Go 语言是特别的一个。Go 语言不需要我们显式的实现类型的接口。如果一个接口里的所有方法都被我们的类型实现了,那么我们就说该类型实现了该接口。 多态: 一种事物的多种形态,都可以按照统一的接口进行操作。 ~~~ package main import "fmt" type Stringer interface { String() string } type Printer interface { Stringer // 接口嵌入。 Print() } type User struct { id int name string } func (self *User) String() string { return fmt.Sprintf("user %d, %s", self.id, self.name) } func (self *User) Print() { fmt.Println(self.String()) } func main() { var t Printer = &User{1, "Tom"} // *User 方法集包含 String、Print。 t.Print() } ~~~ 输出结果: ~~~ user 1, Tom ~~~ 空接口 interface{} 没有任何方法签名,也就意味着任何类型都实现了空接口。其作用类似面向对象语言中的根对象 object。 ~~~ package main import "fmt" func Print(v interface{}) { fmt.Printf("%T: %v\n", v, v) } func main() { Print(1) Print("Hello, World!") } ~~~ 输出结果: ~~~ int: 1 string: Hello, World! ~~~ *匿名接口可用作变量类型,或结构成员。 ~~~ package main import "fmt" type Tester struct { s interface { String() string } } type User struct { id int name string } func (self *User) String() string { return fmt.Sprintf("user %d, %s", self.id, self.name) } func main() { t := Tester{&User{1, "Tom"}} fmt.Println(t.s.String()) } ~~~ 输出结果: ~~~ user 1, Tom ~~~