1.接口定义
最后更新于:2022-04-02 04:44:37
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
~~~
';