Go中关键字interface被赋予了很多不同的含义。每个类型都有接口,意味着对那个类型定义了方法集合。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
type S struct { i int }
func (p *S) Get () int { return p.i }
func (p *S) Put (v int ) { p.i = v }
type I interface {
Get() int
Put(int )
}
func f (p I) {
fmt.Println(p.Get())
p.Put(1 )
}
var s S
f(&s)
type R struct { i int }
func (p *R) Get () int { return p.i }
func (p *R) Put (v int ) { p.i=v }
func f (p I) {
switch t : p.(type ) {
case *S:
case *R:
case S:
case R:
defaut:
}
}
if t, ok := p.(*S); ok {
fmt.Printf("%d\n" , t.Get())
}
t := p.(*S)
空接口 1
2
3
4
5
6
7
8
9
10
interface {}
func g (something interface {}) int {
return something.(I).Get()
}
s = new (S)
fmt.Println(g(s))
i:=5
fmt.Println(g(i))
方法 方法就是有接受者的函数,可以在任意类型上定义方法(除了非本地类型,包括内建类型:int类型不能有方法)。但是可以新建一个拥有方法的整数类型。
1
2
3
4
5
6
7
8
9
10
11
12
type Foo int
func (f Foo) Emit () {
fmt.Printf("%v" ,f)
}
type Emitter interface {
Emit()
}
func (i int ) Emit () {....}
func (a *net.AddrError) Emit () {...}
type newError net.AddrError
func (a *newError) Emit () {...}
接口定义为一个方法的集合。方法包含实际的代码。换句话说,一个接口就是定义,而方法就是实现。因此,接受者不定定义为接口类型,这样做会引起invalid receiver type编译错误
接收者类型必须是 T 或 *T,这里的 T 是类型名。T 叫做接收者基础类型或 简称基础类型。基础类型一定不能使指针或接口类型,并且定义在与方法 相同的包中。
在Go中创建指向接口的指针是无意义的。实际上创建接口值的指针也是非法的。
接口名字 根据规则,单方法接口命名为方法名加上 -er 后缀:Reader,Writer,Formatter 等。 有一堆这样的命名,高效的反映了它们职责和包含的函数名。Read,Write,Close, Flush,String 等等有着规范的声明和含义。为了避免混淆,除非有类似的声明和含 义,否则不要让方法与这些重名。相反的,如果类型实现了与众所周知的类型相同的方 法,那么就用相同的名字和声明;将字符串转换方法命名为 String 而不是 ToString。 冒泡排序整型数据
1
2
3
4
5
6
7
8
9
func bubblesort (n []int ) {
for i:=0 ; i< len (n)-1 ; i++ {
for j:=i+1 ; j< len (n); j++ {
if n[j]<n[i] {
n[i], n[j] = n[j], n[i]
}
}
}
}
类似的排序字符串 func bubblesortString(n []string){ /…. / } 基于此,可能需要两个函数,每个类型一个。而通过使用接口可以让这个变得更加通用。 下面的方法不能用❎
1
2
3
4
5
6
7
8
9
func sort (i []interface {}) {
switch i.(type ) {
case string :
case int :
}
return
}
但是如果用sort([]int{1,4,5})调用这个函数,会失败:cannot use i (type []int) as type []interface in function argment 这是因为Go不能(隐式)转换为slice。 所以需要通过接口的方式创建Go形式的“通用”函数。 步骤: 1.定义一个有着若干排序相关方法的接口函数(这里叫做Sorter)。至少需要获取slice长度的函数,比较两个值的函数和交换函数;
1
2
3
4
5
type Sorter interface {
Len() int
Less(i,j int ) bool
Swap(i,j int )
}
2.定义用于排序slice的新类型。注意定义的是slice类型;
1
2
type Xi []int
type Xs []string
3.实现Sorter接口的方法。
1
2
3
4
5
6
7
8
func (p Xi) Len () int { return len (p) }
func (p Xi) Less (i int , j int ) bool { return p[j]<p[i] }
func (p Xi) Swap (i int , j int ) { p[i],p[j]=p[j],p[i] }
func (p Xs) Len () int { return len (p) }
func (p Xs) Less (i int , j int ) bool { return p[j] < p[i] }
func (p Xs) Swap (i int , j int ) { p[i], p[j] = p[j], p[i]
4.编写作用于Sorter接口的通用排序函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func Sort (x Sorter) {
for i:=0 ; i<x.Len()-1 ; i++ {
for j:=i+1 ; j<x.Len(); j++ {
if x.Less(i, j) {
x.Swap(i, j)
}
}
}
}
ints := Xi{44 , 67 , 3 , 17 , 89 , 10 , 73 , 9 , 14 , 8 }
strings := Xs{"nut" , "ape" , "elephant" , "zoo" , "go" }
Sort(ints)
fmt.Printf("%v\n" , ints)
Sort(strings)
fmt.Printf("%v\n" , strings)