介面定義與實作#
Go 的介面採隱式實作(鴨子型別,Duck Typing):
// 定義介面
type Writer interface {
Write(data []byte) (int, error)
}
type Reader interface {
Read(buf []byte) (int, error)
}
// 介面組合
type ReadWriter interface {
Reader
Writer
}
// 隱式實作
type FileBuffer struct {
data []byte
}
func (f *FileBuffer) Write(data []byte) (int, error) {
f.data = append(f.data, data...)
return len(data), nil
}
func (f *FileBuffer) Read(buf []byte) (int, error) {
n := copy(buf, f.data)
return n, nil
}
// FileBuffer 自動實作了 Writer、Reader、ReadWriterGo 的介面實作不需要
implements關鍵字。只要型別實作了介面定義的所有方法,就自動滿足該介面。
空介面#
interface{} 是空介面,可以儲存任何型別的值:
var any interface{}
any = 42
any = "hello"
any = []int{1, 2, 3}
// Go 1.18+ 可以使用 any 作為 interface{} 的別名
var value any = "test"介面值的內部結構#
介面值由兩部分組成:
// 概念
type iface struct {
tab *itab // 型別資訊
data unsafe.Pointer // 實際值的指標
}var w Writer
var fb *FileBuffer
// w 的 tab 和 data 都是 nil
fmt.Println(w == nil) // true
w = fb // fb 是 nil 指標
// w 的 tab 指向 *FileBuffer 型別資訊
// w 的 data 是 nil
fmt.Println(w == nil) // false!即使把 nil 指標賦值給介面,介面值也不等於 nil。這是非常常見的陷阱,要避免把 nil 指標傳給介面型別。
判斷介面是否真正為空
func IsNil(i interface{}) bool {
if i == nil {
return true
}
v := reflect.ValueOf(i)
switch v.Kind() {
case reflect.Ptr, reflect.Map, reflect.Slice,
reflect.Chan, reflect.Func, reflect.Interface:
return v.IsNil()
}
return false
}