接口是 Go 語言實現?多態?的核心機制。本章將幫助你理解接口的設計哲學、動態行為,以及它如何讓 Go 實現面向接口編程的能力。
一、什么是接口?
接口是一組方法簽名的集合,任何類型只要實現了接口中聲明的所有方法,就被視為實現了該接口,不需要顯式聲明。
接口定義示例:
type?Speaker?interface?{Speak()
}
任何具有?Speak()
?方法的類型,都會被認為實現了?Speaker
?接口。
二、接口的使用
1. 定義接口與實現
type?Animal?interface?{Speak()
}type?Dog?struct{}
func?(d?Dog)?Speak()?{fmt.Println("Woof!")
}type?Cat?struct{}
func?(c?Cat)?Speak()?{fmt.Println("Meow!")
}
2. 接口變量與多態調用
func?MakeSound(a?Animal)?{a.Speak()
}func?main()?{var?d?Dogvar?c?CatMakeSound(d)?//?Woof!MakeSound(c)?//?Meow!
}
這就是多態:一個接口類型變量?
a
,可以代表多個實現了該接口的類型(如 Dog、Cat)。
三、接口值的底層機制(簡要)
接口類型的變量底層由兩部分組成:
- ??
動態類型
:接口實際指向的具體類型 - ??
動態值
:接口存儲的具體值
這讓接口可以靈活綁定不同實現,但仍保持統一調用接口方法的行為。
四、接口組合(interface embedding)
接口之間也可以組合:
type?Reader?interface?{Read(p?[]byte)?(n?int,?err?error)
}type?Writer?interface?{Write(p?[]byte)?(n?int,?err?error)
}type?ReadWriter?interface?{ReaderWriter
}
任何類型只要實現了?Read()
?和?Write()
?方法,就實現了?ReadWriter
?接口。
五、接口的動態行為與?nil
?陷阱
var?a?Animal?=?nil
fmt.Println(a?==?nil)?//?truevar?d?*Dog?=?nil
a?=?d
fmt.Println(a?==?nil)?//?false!
原因:接口變量?
a
?本身不為 nil,它的動態類型是?*Dog
,只是動態值為 nil。
解決:使用類型斷言判斷實際是否為 nil。
六、接口與工廠模式
接口是 Go 中實現解耦的核心工具,適合用于構建靈活的“工廠”類模式:
type?Shape?interface?{Area()?float64
}type?Circle?struct?{Radius?float64
}func?(c?Circle)?Area()?float64?{return?3.14?*?c.Radius?*?c.Radius
}func?NewShape(name?string)?Shape?{switch?name?{case?"circle":return?Circle{Radius:?5}default:return?nil}
}
七、小結
概念 | 說明 |
接口 | 方法集合的抽象,任何實現了接口方法的類型都符合接口 |
多態 | 同一接口變量可綁定不同實現類型,統一調用方式 |
接口組合 | 可通過嵌套組合多個接口 |
接口工廠模式 | 常用于隱藏具體實現,返回接口類型以實現解耦 |
nil ?陷阱 | 接口變量底層包含“類型+值”,判斷 nil 時需注意 |