Go 中的 interface 是一种抽象类型。一个 interface 就是包含了一系列行为的method集合。 关于 interface 的定义,以 Writer 为例:
package io
type Writer interface {
Write(p []byte) (n int, err error)
}
Go 中的 interface 属于隐式接口。一个类型如果拥有一个接口需要的所有方法,那么这个类型就实现了这个接口。
在标准库 fmt 包中的一系列方法可以很好地诠释 interface 是如何应用到实践当中的。
package fmt
func Fprintf(w io.Writer, format string, args ...interface{}) (int, error)
func Printf(format string, args ...interface{}) (int, error) {
return Fprintf(os.Stdout, format, args...)
}
func Sprintf(format string, args ...interface{}) string {
var buf bytes.Buffer
Fprintf(&buf, format, args...)
return buf.String()
}
Fprintf 的前缀 F 表示文件(File)也表明格式化输出结果应该被写入第一个参数提供的文件中。
在Printf函数中的第一个参数os.Stdout是*os.File类型;
在sprintf函数中的第一个参数&buf是一个指针,指向可以写入字节的内存缓冲区;
而Fprintf函数中的第一个参数是一个 interface 类型 io.Writer。io.Writer 定义了函数 Fprintf 和这个函数调用者之间的约定,该约定保证了 Fprintf 接受任何满足 io.Writer 接口的值。
因为 fmt.Fprintf 函数没有对具体操作的值做任何假设而是进京通过 io.Writer 接口的约定来保证行为,所以第一个参数可以安全地传入任何一个具体类型的值,只需要它能满足 io.Writer 接口。
一个类型可以自由的使用另一个满足相同接口的类型来进行替换被称作可替换性(LSP里氏替换)。这是一个面向对象的特征。
定义 interface
以标准库中的 io 包为例, io 包中定义了很多有用的 interface :
package io
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
}
/* Reader 代表任何可以去读 byte 的类型, Writer 代表任何可以写入 byte 的类型, Closer 代表任何可以执行 close 的类型 */
除此之外,还能在 io 包中发现其他组合式的 interface:
package io
type ReaderWriter interface {
Reader
Writer
}
type ReadWriteCloser interface {
Reader
Writer
Closer
}
/*该语法和结构体内嵌相似,可以用这种方式简写命名一个接口,称为接口内嵌*/
实现接口的条件
一个类型如果拥有一个接口需要的所有方法,那么这个类型就实现了这个接口。
接口指定的规则也非常简单:表达一个类型属于某个接口只要这个类型实现这个接口,所以:
var w io.Writer
w = os.Stdout //OK: *os.File has Write method
w = new(bytes.Buffer) //OK: *bytes.Buffer has write method
w = time.Second //compile error: time.Duration lacks Write method
var rwc io.ReadWriteCloser
rwc = os.Stdout //OK: *os.File has Read, Write, Close methods
rwc = new(bytes.Buffer)//compile error: *bytes.Buffer lacks Close method
/* 这个规则甚至适用于等式右边本身也是一个接口类型 */
w = rwc // OK: io.ReadWriteCloser has Write method
rwc = w // compile error: io.Writer lacks Close method