接口
接口类型是对其他类型行为的概括与抽象。我们可以通过接口来约定某一类通用行为。Go语言的接口是隐式的:只要实现接口A的所有方法就代表实现了接口A。
接口即约定
接口是什么样的?
package io
// 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)
}
这是标准库的一个接口,他定义了一个方法Write
来约定我们如果想实现写接口
需要怎么做。
书中举了fmt.Printf
和fmt.Sprintf
的例子,他们的相同点是实现了字符串的格式化,不同点是对格式化结果的行为,前者是发到标准输出,后者是以string
类型返回。标准库肯定不会将相同的部分两边,它是这样做的:用第三个函数Fprintf
来封装格式化,并且将对格式化后的结果的行为收拢成“将结果写到一个地方”(即定义接口Writer
),至于这个地方是哪里的问题丢给了调用方(即通过接口来约定调用者必须传递一个实现接口Writer
的类型),调用者可以把结果写到标准输出(即fmt.Printf
),调用者也可以把结果写到某个buffer里(即fmt.Sprintf
)。这样的解法便达到了复用且灵活。
package fmt
func Fprintf(w io.Writer, format string, args ...interface{}) (int, error) {
// 格式化
w.Write()
//...
}
func Printf(fomrat 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()
}
思考
接口的写法与实现很简单,难的是接口的定义与接口的使用。接口的定义是对许多具象使用场景的抽象,接口的目的是什么?接口以后的适用场景是哪些?在实现接口的方法是要注意什么?这写都应该在接口定义的注释中写明。