Go?Interface接口初學者手冊
Interface接口類型實現
接口是一組方法簽名。如果一個類型在其上定義了給定接口的所有方法,則該類型 "實現" 了該接口。
在以下示例中,“形狀” 必須能夠返回其面積和周長。rect 和 circle 都滿足該接口。
type shape interface {
area() float64
perimeter() float64
}
type rect struct {
width, height float64
}
func (r rect) area() float64 {
return r.width * r.height
}
func (r rect) perimeter() float64 {
return 2*r.width + 2*r.height
}
type circle struct {
radius float64
}
func (c circle) area() float64 {
return math.Pi * c.radius * c.radius
}
func (c circle) perimeter() float64 {
return 2 * math.Pi * c.radius
}當一個類型實現一個接口時,它可以被用作該接口類型。
接口的實現是隱式的。
類型從不聲明它實現了給定的接口。如果接口存在,并且類型定義了適當的方法,那么該類型會自動滿足該接口。
Multiple Interfaces
在Go中,一個類型可以實現任意數量的接口。例如,空接口 interface{} 總是被每種類型實現,因為它沒有要求。
Naming interface args
考慮以下接口:
type Copier interface {
Copy(string, string) int
}根據僅有的代碼,你能推斷出應該將什么類型的字符串傳遞給 Copy 函數嗎?
我們知道函數簽名期望兩個字符串類型,但它們是什么?文件名?URL?原始字符串數據?另外,返回的那個整數到底是什么?
讓我們添加一些有名的參數和返回數據,使其更清晰。
type Copier interface {
Copy(sourceFile string, destinationFile string) (bytesCopied int)
}好多了。現在我們可以看到期望是什么了。第一個參數是 sourceFile,第二個參數是 destinationFile,并返回了一個整數 bytesCopied。
Type Assertions in Go
在Go中使用接口時,偶爾需要訪問接口值的底層類型。您可以使用類型斷言將接口轉換為其底層類型。
type shape interface {
area() float64
}
type circle struct {
radius float64
}
// "c" is a new circle cast from "s"
// which is an instance of a shape.
// "ok" is a bool that is true if s was a circle
// or false if s isn't a circle
c, ok := s.(circle)
if !ok {
// s wasn't a circle
log.Fatal("s is not a circle")
}
radius := c.radiusType Switches in Go
類型開關使得在一系列中執(zhí)行多個類型斷言變得很容易。
類型開關類似于常規(guī)的開關語句,但是情況指定的是類型而不是值。
func printNumericValue(num interface{}) {
switch v := num.(type) {
case int:
fmt.Printf("%T\n", v)
case string:
fmt.Printf("%T\n", v)
default:
fmt.Printf("%T\n", v)
}
}
func main() {
printNumericValue(1)
// prints "int"
printNumericValue("1")
// prints "string"
printNumericValue(struct{}{})
// prints "struct {}"
}fmt.Printf("%T\n", v) 打印變量的類型。
Clean Interfaces
編寫清晰的接口很難。坦率地說,每當在代碼中處理抽象概念時,如果不小心,簡單的事情很快就會變得復雜。讓我們回顧一些保持接口清晰的經驗法則。
Keep Interfaces Small
如果你從這篇文章中只記住一點建議,那就是:保持接口的小巧!接口的目的是定義準確表示一個想法或概念所需的最小行為。
以下是標準 HTTP 包中的一個較大接口的示例,它很好地演示了定義最小行為的概念:
type File interface {
io.Closer
io.Reader
io.Seeker
Readdir(count int) ([]os.FileInfo, error)
Stat() (os.FileInfo, error)
}滿足接口行為的任何類型都可以被 HTTP 包視為 File。這很方便,因為 HTTP 包不需要知道它處理的是磁盤上的文件,網絡緩沖區(qū)還是簡單的 []byte。
Interfaces Should Have No Knowledge of Satisfying Types
接口應該定義其他類型需要滿足的條件以成為該接口的成員。它們在設計時不應該知道任何恰好滿足該接口的類型。
例如,假設我們正在構建一個描述定義汽車所需組件的接口。
type car interface {
Color() string
Speed() int
IsFiretruck() bool
}Color() 和 Speed() 完全有道理,它們是限定在汽車范圍內的方法。IsFiretruck() 是一個反模式。我們強制所有汽車聲明它們是否是消防車。為了使這種模式有任何意義,我們需要一個可能的子類型清單。IsPickup()、IsSedan()、IsTank()... 這會無休止地擴展。
相反,開發(fā)人員應該依賴于類型斷言的本機功能,在給定汽車接口的實例時推導出底層類型。或者,如果需要子接口,可以這樣定義:
type firetruck interface {
car
HoseLength() int
}這個接口繼承了 car 所需的方法,并添加了一個額外的必需方法,使車輛成為消防車。
Interfaces Are Not Classes
接口不是類,它們更加輕量。
接口沒有構造函數或析構函數,不要求創(chuàng)建或銷毀數據。
接口在本質上不是層次結構,盡管有語法糖可以創(chuàng)建接口,這些接口碰巧是其他接口的超集。
接口定義了函數簽名,但不定義底層行為。創(chuàng)建接口通常不會在結構方法方,使代碼更加干燥。例如,如果有五種類型滿足 fmt.Stringer 接口,它們都需要有自己版本的 String() 函數。
以上就是Go Interfaces接口初學者手冊的詳細內容,更多關于Go Interfaces接口的資料請關注腳本之家其它相關文章!
相關文章
Golang?手寫一個簡單的并發(fā)任務?manager
這篇文章主要介紹了Golang?手寫一個簡單的并發(fā)任務?manager,文章圍繞主題展開詳細的內容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-08-08

