接口
接口類型是對其他類型行為的概括與抽象。我們可以通過接口來約定某一類通用行為。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()
}
思考
接口的寫法與實現很簡單,難的是接口的定義與接口的使用。接口的定義是對許多具象使用場景的抽象,接口的目的是什么?接口以后的適用場景是哪些?在實現接口的方法是要注意什么?這寫都應該在接口定義的注釋中寫明。