go20/day05/interface/README.md
yumaojun03 aa35d086f8 ```
feat(interface): 添加Go语言接口教程和示例代码

添加了完整的Go语言接口教学内容,包括:

- README.md中详细介绍了Go语言接口的概念和特性
- 包含解耦、多态、扩展性等接口优势说明
- 提供面向接口编程的完整示例代码
- 展示了标准库中Reader、Writer等常用接口
- 实现了一个支持Reader和Writer接口的Buffer示例
- 在main.go中演示了接口的实际应用和类型断言用法
```
2026-02-08 16:44:15 +08:00

313 lines
8.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Go语言接口
[课件](https://gitee.com/infraboard/go-course/blob/master/zh-cn/base/interface.md)
+ 解耦Decoupling调用者不需要知道具体类型只需要知道接口
+ 多态Polymorphism不同类型可以有相同的接口统一处理
+ 扩展性Extensibility新增类型时不需要修改已有代码
## 面向接口
```go
package main
import "fmt"
func main() {
//
dog := Dog{Name: "旺财"}
fmt.Println(dog.Speak())
//
cat := Cat{Name: "招财猫"}
fmt.Println(cat.Speak())
//
cow := Cow{Name: "小牛"}
fmt.Println(cow.Speak())
// 必须知道对象的对象, 才能调用, 面向具体类型来编写代码, 依赖具体类型, 耦合度高
// 没有一层统一抽象,上层业务逻辑,需要知道对象,才能调用,非常麻烦,高耦合
// speakers := []interface{}{dog, cat, cow}
// for _, speaker := range speakers {
// switch speaker.(type) {
// case Dog:
// fmt.Println(speaker.(Dog).Speak())
// case Cat:
// fmt.Println(speaker.(Cat).Speak())
// case Cow:
// fmt.Println(speaker.(Cow).Speak())
// }
// //...
// }
// 管理员,组织这些演技者,进行演讲
// interface 先制定规范, 底层系统按照规范进行实现,上层业务代码的编写将会是透明的,简单高效
// 这里的Speaker 和 Dog Cat Cow 都是type 他们是一种东西吗?
// speakers = []Dog{}{dog1,dog2, dog3}
// Speaker 是一种约束, 约束放入这个slice里面的对象必须实现这个接口的所有方法
speakers := []Speaker{dog, cat, cow}
for _, speaker := range speakers {
fmt.Println(speaker.Speak())
}
// 只关注 方法(接口), 不关注 对象的编程的方式,就是面向接口
}
// 任何一个结构体 实现了这个接口的所有方法, 就实现了这个接口
// 接口是一层抽象, 只要实现了这个接口的所有方法, 就可以被当做这个接口来使用,屏蔽了底层系统
type Speaker interface {
Speak() string // 说话方法
GetName() string // 获取名字方法
}
// 2. 定义不同的类型
type Dog struct {
Name string
}
// 3. 实现接口方法
func (d Dog) Speak() string {
return "汪汪汪"
}
func (d Dog) GetName() string {
return d.Name
}
type Cat struct {
Name string
}
func (c Cat) Speak() string {
return "喵喵喵"
}
func (c Cat) GetName() string {
return c.Name
}
type Cow struct {
Name string
}
func (c Cow) Speak() string {
return "哞哞哞"
}
func (c Cow) GetName() string {
return c.Name
}
```
+ 解耦: 调用者不需要知道具体类型,只需要知道接口, fmt.Println(speaker.Speak())
+ 多态Polymorphism不同类型可以有相同的接口统一处理, []Speaker{dog, cat, cow}
+ 扩展性Extensibility新增类型时不需要修改已有代码
+ Go语言的接口实现是隐式的, 底层系统按照规范进行实现,上层业务代码的编写将会是透明的,简单高效
## 面向接口
```go
type Reader interface {
Read(p []byte) (n int, err error)
}
// Writer is the interface that wraps the basic Write method.
//
// Write writes len(p) bytes from p to the underlying data stream.
// It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// Write must return a non-nil error if it returns n < len(p).
// Write must not modify the slice data, even temporarily.
//
// Implementations must not retain p.
type Writer interface {
Write(p []byte) (n int, err error)
}
// Closer is the interface that wraps the basic Close method.
//
// The behavior of Close after the first call is undefined.
// Specific implementations may document their own behavior.
type Closer interface {
Close() error
}
// Seeker is the interface that wraps the basic Seek method.
//
// Seek sets the offset for the next Read or Write to offset,
// interpreted according to whence:
// [SeekStart] means relative to the start of the file,
// [SeekCurrent] means relative to the current offset, and
// [SeekEnd] means relative to the end
// (for example, offset = -2 specifies the penultimate byte of the file).
// Seek returns the new offset relative to the start of the
// file or an error, if any.
//
// Seeking to an offset before the start of the file is an error.
// Seeking to any positive offset may be allowed, but if the new offset exceeds
// the size of the underlying object the behavior of subsequent I/O operations
// is implementation-dependent.
type Seeker interface {
Seek(offset int64, whence int) (int64, error)
}
// ReadWriter is the interface that groups the basic Read and Write methods.
type ReadWriter interface {
Reader
Writer
}
// ReadCloser is the interface that groups the basic Read and Close methods.
type ReadCloser interface {
Reader
Closer
}
// WriteCloser is the interface that groups the basic Write and Close methods.
type WriteCloser interface {
Writer
Closer
}
// ReadWriteCloser is the interface that groups the basic Read, Write and Close methods.
type ReadWriteCloser interface {
Reader
Writer
Closer
}
// ReadSeeker is the interface that groups the basic Read and Seek methods.
type ReadSeeker interface {
Reader
Seeker
}
// ReadSeekCloser is the interface that groups the basic Read, Seek and Close
// methods.
type ReadSeekCloser interface {
Reader
Seeker
Closer
}
// WriteSeeker is the interface that groups the basic Write and Seek methods.
type WriteSeeker interface {
Writer
Seeker
}
// ReadWriteSeeker is the interface that groups the basic Read, Write and Seek methods.
type ReadWriteSeeker interface {
Reader
Writer
Seeker
}
```
Io Reader和Writer接口
```go
// Reader is the interface that wraps the basic Read method.
//
// Read reads up to len(p) bytes into p. It returns the number of bytes
// read (0 <= n <= len(p)) and any error encountered. Even if Read
// returns n < len(p), it may use all of p as scratch space during the call.
// If some data is available but not len(p) bytes, Read conventionally
// returns what is available instead of waiting for more.
//
// When Read encounters an error or end-of-file condition after
// successfully reading n > 0 bytes, it returns the number of
// bytes read. It may return the (non-nil) error from the same call
// or return the error (and n == 0) from a subsequent call.
// An instance of this general case is that a Reader returning
// a non-zero number of bytes at the end of the input stream may
// return either err == EOF or err == nil. The next Read should
// return 0, EOF.
//
// Callers should always process the n > 0 bytes returned before
// considering the error err. Doing so correctly handles I/O errors
// that happen after reading some bytes and also both of the
// allowed EOF behaviors.
//
// If len(p) == 0, Read should always return n == 0. It may return a
// non-nil error if some error condition is known, such as EOF.
//
// Implementations of Read are discouraged from returning a
// zero byte count with a nil error, except when len(p) == 0.
// Callers should treat a return of 0 and nil as indicating that
// nothing happened; in particular it does not indicate EOF.
//
// Implementations must not retain p.
type Reader interface {
Read(p []byte) (n int, err error)
}
// Writer is the interface that wraps the basic Write method.
//
// Write writes len(p) bytes from p to the underlying data stream.
// It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// Write must return a non-nil error if it returns n < len(p).
// Write must not modify the slice data, even temporarily.
//
// Implementations must not retain p.
type Writer interface {
Write(p []byte) (n int, err error)
}
```
如何实现一个buf
```go
func NewBuffer() *Buffer {
return &Buffer{
// 固定 1k 大小的缓冲区
buf: make([]byte, 1024),
dataLen: 0,
}
}
// 实现 Reader和 Writer方法
type Buffer struct {
buf []byte // 固定大小的缓冲区
dataLen int // 当前缓冲区中的数据量
}
func (b *Buffer) Read(p []byte) (n int, err error) {
if b.dataLen == 0 {
return 0, io.EOF
}
// 读取缓冲区中的数据
n = copy(p, b.buf[:b.dataLen])
fmt.Println("read: ", n)
// 移除已读数据(将未读数据前移)
copy(b.buf, b.buf[n:b.dataLen])
b.dataLen -= n
return n, nil
}
func (b *Buffer) Write(p []byte) (n int, err error) {
// 计算剩余空间
available := len(b.buf) - b.dataLen
if available == 0 {
// 缓冲区已满
return 0, io.ErrShortBuffer
}
// 只写入缓冲区能容纳的数据(固定大小,不扩展)
n = copy(b.buf[b.dataLen:], p)
b.dataLen += n
fmt.Printf("write: %d 字节, 缓冲区使用: %d/%d\n", n, b.dataLen, len(b.buf))
// 如果没能写入全部数据,返回 ErrShortBuffer
if n < len(p) {
return n, io.ErrShortBuffer
}
return n, nil
}
func (b *Buffer) String() string {
return string(b.buf[:b.dataLen])
}
// Reset 清空缓冲区
func (b *Buffer) Reset() {
b.dataLen = 0
}
```