接口
在使用 type 进行定义时,类型为 interface 的对象叫做接口:
type Writer interface { // 类型为 interface, 是接口
}
接口内部会放置 2 类内容:
- 接口函数
- 接口内嵌
接口函数
type Writer interface {
Write(p []byte) (n int, err error) // 接口函数
}
接口内嵌
package io
type Reader interface {
Read(p []byte)(n int, err error)
}
type ReadWriter interface {
Reader // 已有接口类型
Writer 已有接口类型
}
实现接口的条件
唯一的要求是类型 A 要拥有类型 B 需要的所有方法。
var w io.Writer
w = os.Stdout // *os.File 拥有 Writer 方法
w = new(bytes.Buffer) // *bytes.Buffer 拥有 Writer 方法
w = time.Second // 编译错误,time.Duration 缺少 Writer 方法
var rwc io.ReadWriteCloser
rwc = os.Stdout // *os.File 有 Read, Write, Close 方法
rwc = new(bytes.Buffer) // 编译错误,bytes.Buffer 缺少 Close 方法
w = rwc // io.ReadWriteCloser 有 Write 方法
rwc = w // 编译错误,io.Writer 缺少 Close 方法
type IntSet struct {/* ... */}
func (*IntSet) String() string
var _ = IntSet{}.String() // 编译错误,String 需要指针 *IntSet
这里函数定义的是 *IntSet 进行调用,而实际使用的是 IntSet{} 。
var s IntSet
var _ = s.String() // s 此时就是 IntSet 指针,取它的地址 &s 就能得到 IntSet 类型的 String 方法
var _ fmt.Stringer = &s // *IntSet 有 String 方法,通过
var _ fmt.Stringer = s // 编译错误,IntSet 缺少 String 方法
接口的特点有 2 个:
- 隐藏类型 A 原有的方法
- 任意值赋给空接口类型
隐藏类型 A 原有的方法
os.Stdout.Write([]byte("hello")) // os.Stdout 拥有 Write 方法
os.Stdout.Close() // os.Stdout 拥有 Close 方法
var w io.Writer
w = os.Stdout
w.Write([]byte("hello")) // io.Writer 有 Writer ,通过
w.Close() // 编译错误,因为 io.Writer 中没有 Close 方法,因此将 os.Stdout 的方法也隐藏了
任意值赋给空接口类型
var any interface{}
any = true
any = 12.34
any = "hello"
any = map[string]int{"one":1}
any = new(bytes.Buffer)
实例:
type Artifact interface {
Title() string
Creators() []string
Created() time.Time
}
type Text interface {
Pages() int
Words() int
PageSize() int
}
type Audio interface {
Stream() (io.ReadCloser, error)
RunningTime() time.Duration
Format() string // eg. "MP3", "WAV"
}
type Video interface {
Stream() (io.ReadCloser, error)
RunningTime() time.Duration
Format() string // eg. "MP4", "WMV"
Resolution() (x, y, int)
}
// 可以将 Audio 和 Video 定义一个 Streamer 接口,代表它们之间相同的部分
type Streamer interface {
Stream()(io.ReadCloser, error)
RunningTime() time.Duration
Format() string
}