第20章 接口实现
第20章 接口实现
Go语言的接口实现机制是"隐式的",不需要implements关键字。只要方法签名对上了,编译器就会认可你"实现了"那个接口。这种设计叫做鸭子类型(Duck Typing)——“如果它走起来像鸭子,叫起来像鸭子,那它就是鸭子。”
20.1 隐式实现原理
20.1.1 什么是隐式实现
在其他语言(如Java)中,你要实现一个接口,得显式声明。但在Go中,你只需要把方法实现好,编译器会自动认为你实现了接口:
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
| package main
import "fmt"
type Writer interface {
Write(p []byte) (n int, err error)
}
type File struct {
name string
}
func (f *File) Write(p []byte) (n int, err error) {
fmt.Printf("[File] 写入文件 %s: %s\n", f.name, string(p)) // [File] 写入文件 test.txt: Hello, Go!
return len(p), nil
}
type StringWriter struct{}
func (s *StringWriter) Write(p []byte) (n int, err error) {
fmt.Printf("[StringWriter] 写入字符串: %s\n", string(p)) // [StringWriter] 写入字符串: Another message
return len(p), nil
}
func main() {
var w Writer = &File{name: "test.txt"}
w.Write([]byte("Hello, Go!"))
var sw Writer = &StringWriter{}
sw.Write([]byte("Another message"))
}
|
20.1.2 方法匹配规则
Go的接口实现要求方法完全匹配:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| package main
import "fmt"
type Reader interface {
Read(p []byte) (n int, err error)
}
type RightReader struct{}
func (r *RightReader) Read(p []byte) (n int, err error) {
copy(p, []byte("correct data"))
return len("correct data"), nil
}
func main() {
var r Reader = &RightReader{}
buf := make([]byte, 100)
n, _ := r.Read(buf)
fmt.Printf("读取了 %d 字节: %s\n", n, string(buf[:n])) // 读取了 12 字节: correct data
}
|
20.2 实现方式:值接收者 vs 指针接收者
20.2.1 值接收者实现
使用值接收者定义的方法,值类型和指针类型都算实现了接口:
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
| package main
import "fmt"
type ReadOnly interface {
Read(p []byte) (n int, err error)
}
type Document struct {
content string
}
func (d Document) Read(p []byte) (n int, err error) {
copy(p, d.content)
return len(d.content), nil
}
func main() {
doc := Document{content: "Hello, World!"}
var ro1 ReadOnly = doc
buf := make([]byte, 100)
n, _ := ro1.Read(buf)
fmt.Printf("值类型赋值,读取内容: %s\n", string(buf[:n])) // 值类型赋值,读取内容: Hello, World!
doc2 := Document{content: "Pointer case"}
var ro2 ReadOnly = &doc2
n, _ = ro2.Read(buf)
fmt.Printf("指针类型赋值,读取内容: %s\n", string(buf[:n])) // 指针类型赋值,读取内容: Pointer case
}
|
20.2.2 指针接收者实现
使用指针接收者定义的方法,只有指针类型实现了接口:
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
| package main
import "fmt"
type Writable interface {
Write(p []byte) (n int, err error)
}
type Buffer struct {
data []byte
}
func (b *Buffer) Write(p []byte) (n int, err error) {
b.data = append(b.data, p...)
fmt.Printf("[Buffer] 写入 %d 字节\n", len(p)) // [Buffer] 写入 7 字节
return len(p), nil
}
func main() {
buf := &Buffer{}
var w Writable = buf
w.Write([]byte("Hello, "))
w.Write([]byte("World!"))
fmt.Printf("\nBuffer内容: %s\n", string(buf.data)) // Buffer内容: Hello, World!
}
|
20.2.3 方法集规则
| 接收者类型 | 值接收者方法 | 指针接收者方法 |
|---|
值类型 T | ✅ | ❌ |
指针类型 *T | ✅ | ✅ |
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
| package main
import "fmt"
type Operations interface {
Process()
GetValue() int
}
type Counter struct {
value int
}
func (c Counter) GetValue() int {
return c.value
}
func (c *Counter) Process() {
c.value++
}
func main() {
var ops1 Operations = &Counter{value: 10}
ops1.Process()
fmt.Printf("指针赋值: %d\n", ops1.GetValue()) // 指针赋值: 11
}
|
20.3 接口实现的实际应用
20.3.1 同一类型实现多个接口
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
44
45
46
47
48
49
| package main
import "fmt"
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
type Closer interface {
Close() error
}
type File struct {
name string
data []byte
}
func (f *File) Read(p []byte) (n int, err error) {
copy(p, f.data)
fmt.Printf("[File.Read] 读取文件 %s\n", f.name) // [File.Read] 读取文件 data.txt
return len(f.data), nil
}
func (f *File) Write(p []byte) (n int, err error) {
f.data = append(f.data, p...)
fmt.Printf("[File.Write] 写入文件 %s: %s\n", f.name, string(p)) // [File.Write] 写入文件 data.txt: Hello
return len(p), nil
}
func (f *File) Close() error {
fmt.Printf("[File.Close] 关闭文件 %s\n", f.name) // [File.Close] 关闭文件 data.txt
return nil
}
func main() {
f := &File{name: "data.txt", data: []byte("Hello")}
var r Reader = f
var w Writer = f
var c Closer = f
r.Read(make([]byte, 100))
w.Write([]byte(" World"))
c.Close()
}
|
20.3.2 验证接口实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| package main
import "io"
type NullWriter struct{}
func (n *NullWriter) Write(p []byte) (int, error) {
return len(p), nil
}
var _ io.Writer = (*NullWriter)(nil)
func main() {
w := &NullWriter{}
n, _ := w.Write([]byte("test"))
println("写入字节数:", n) // 写入字节数: 4
}
|
本章小结
本章我们学习了Go接口的隐式实现机制:
核心原理:
- Go使用隐式接口实现,不需要
implements关键字 - 只要方法签名匹配,编译器就认为类型实现了接口
方法集规则:
- 值类型
T只能实现值接收者方法 - 指针类型
*T可以实现所有方法
实用技巧:
- 使用
var _ Interface = (*Type)(nil)进行编译时接口验证 - 同一类型可以实现多个接口