99re热这里只有精品视频,7777色鬼xxxx欧美色妇,国产成人精品一区二三区在线观看,内射爽无广熟女亚洲,精品人妻av一区二区三区

Go 語言 實現(xiàn)接口的條件

2023-03-14 16:54 更新

原文鏈接:https://gopl-zh.github.io/ch7/ch7-03.html


7.3. 實現(xiàn)接口的條件

一個類型如果擁有一個接口需要的所有方法,那么這個類型就實現(xiàn)了這個接口。例如,*os.File類型實現(xiàn)了io.Reader,Writer,Closer,和ReadWriter接口。*bytes.Buffer實現(xiàn)了Reader,Writer,和ReadWriter這些接口,但是它沒有實現(xiàn)Closer接口因為它不具有Close方法。Go的程序員經(jīng)常會簡要的把一個具體的類型描述成一個特定的接口類型。舉個例子,*bytes.Buffer是io.Writer;*os.Files是io.ReadWriter。

接口指定的規(guī)則非常簡單:表達一個類型屬于某個接口只要這個類型實現(xiàn)這個接口。所以:

var w io.Writer
w = os.Stdout           // OK: *os.File has Write method
w = new(bytes.Buffer)   // OK: *bytes.Buffer has Write method
w = time.Second         // compile error: time.Duration lacks Write method

var rwc io.ReadWriteCloser
rwc = os.Stdout         // OK: *os.File has Read, Write, Close methods
rwc = new(bytes.Buffer) // compile error: *bytes.Buffer lacks Close method

這個規(guī)則甚至適用于等式右邊本身也是一個接口類型

w = rwc                 // OK: io.ReadWriteCloser has Write method
rwc = w                 // compile error: io.Writer lacks Close method

因為ReadWriter和ReadWriteCloser包含有Writer的方法,所以任何實現(xiàn)了ReadWriter和ReadWriteCloser的類型必定也實現(xiàn)了Writer接口

在進一步學(xué)習(xí)前,必須先解釋一個類型持有一個方法的表示當(dāng)中的細節(jié)。回想在6.2章中,對于每一個命名過的具體類型T;它的一些方法的接收者是類型T本身然而另一些則是一個*T的指針。還記得在T類型的參數(shù)上調(diào)用一個*T的方法是合法的,只要這個參數(shù)是一個變量;編譯器隱式的獲取了它的地址。但這僅僅是一個語法糖:T類型的值不擁有所有*T指針的方法,這樣它就可能只實現(xiàn)了更少的接口。

舉個例子可能會更清晰一點。在第6.5章中,IntSet類型的String方法的接收者是一個指針類型,所以我們不能在一個不能尋址的IntSet值上調(diào)用這個方法:

type IntSet struct { /* ... */ }
func (*IntSet) String() string
var _ = IntSet{}.String() // compile error: String requires *IntSet receiver

但是我們可以在一個IntSet變量上調(diào)用這個方法:

var s IntSet
var _ = s.String() // OK: s is a variable and &s has a String method

然而,由于只有*IntSet類型有String方法,所以也只有*IntSet類型實現(xiàn)了fmt.Stringer接口:

var _ fmt.Stringer = &s // OK
var _ fmt.Stringer = s  // compile error: IntSet lacks String method

12.8章包含了一個打印出任意值的所有方法的程序,然后可以使用godoc -analysis=type tool(§10.7.4)展示每個類型的方法和具體類型和接口之間的關(guān)系

就像信封封裝和隱藏起信件來一樣,接口類型封裝和隱藏具體類型和它的值。即使具體類型有其它的方法,也只有接口類型暴露出來的方法會被調(diào)用到:

os.Stdout.Write([]byte("hello")) // OK: *os.File has Write method
os.Stdout.Close()                // OK: *os.File has Close method

var w io.Writer
w = os.Stdout
w.Write([]byte("hello")) // OK: io.Writer has Write method
w.Close()                // compile error: io.Writer lacks Close method

一個有更多方法的接口類型,比如io.ReadWriter,和少一些方法的接口類型例如io.Reader,進行對比;更多方法的接口類型會告訴我們更多關(guān)于它的值持有的信息,并且對實現(xiàn)它的類型要求更加嚴格。那么關(guān)于interface{}類型,它沒有任何方法,請講出哪些具體的類型實現(xiàn)了它?

這看上去好像沒有用,但實際上interface{}被稱為空接口類型是不可或缺的。因為空接口類型對實現(xiàn)它的類型沒有要求,所以我們可以將任意一個值賦給空接口類型。

var any interface{}
any = true
any = 12.34
any = "hello"
any = map[string]int{"one": 1}
any = new(bytes.Buffer)

盡管不是很明顯,從本書最早的例子中我們就已經(jīng)在使用空接口類型。它允許像fmt.Println或者5.7章中的errorf函數(shù)接受任何類型的參數(shù)。

對于創(chuàng)建的一個interface{}值持有一個boolean,float,string,map,pointer,或者任意其它的類型;我們當(dāng)然不能直接對它持有的值做操作,因為interface{}沒有任何方法。我們會在7.10章中學(xué)到一種用類型斷言來獲取interface{}中值的方法。

因為接口與實現(xiàn)只依賴于判斷兩個類型的方法,所以沒有必要定義一個具體類型和它實現(xiàn)的接口之間的關(guān)系。也就是說,有意地在文檔里說明或者程序上斷言這種關(guān)系偶爾是有用的,但程序上不強制這么做。下面的定義在編譯期斷言一個*bytes.Buffer的值實現(xiàn)了io.Writer接口類型:

// *bytes.Buffer must satisfy io.Writer
var w io.Writer = new(bytes.Buffer)

因為任意*bytes.Buffer的值,甚至包括nil通過(*bytes.Buffer)(nil)進行顯示的轉(zhuǎn)換都實現(xiàn)了這個接口,所以我們不必分配一個新的變量。并且因為我們絕不會引用變量w,我們可以使用空標(biāo)識符來進行代替。總的看,這些變化可以讓我們得到一個更樸素的版本:

// *bytes.Buffer must satisfy io.Writer
var _ io.Writer = (*bytes.Buffer)(nil)

非空的接口類型比如io.Writer經(jīng)常被指針類型實現(xiàn),尤其當(dāng)一個或多個接口方法像Write方法那樣隱式的給接收者帶來變化的時候。一個結(jié)構(gòu)體的指針是非常常見的承載方法的類型。

但是并不意味著只有指針類型滿足接口類型,甚至連一些有設(shè)置方法的接口類型也可能會被Go語言中其它的引用類型實現(xiàn)。我們已經(jīng)看過slice類型的方法(geometry.Path,§6.1)和map類型的方法(url.Values,§6.2.1),后面還會看到函數(shù)類型的方法的例子(http.HandlerFunc,§7.7)。甚至基本的類型也可能會實現(xiàn)一些接口;就如我們在7.4章中看到的time.Duration類型實現(xiàn)了fmt.Stringer接口。

一個具體的類型可能實現(xiàn)了很多不相關(guān)的接口??紤]在一個組織出售數(shù)字文化產(chǎn)品比如音樂,電影和書籍的程序中可能定義了下列的具體類型:

Album
Book
Movie
Magazine
Podcast
TVEpisode
Track

我們可以把每個抽象的特點用接口來表示。一些特性對于所有的這些文化產(chǎn)品都是共通的,例如標(biāo)題,創(chuàng)作日期和作者列表。

type Artifact interface {
    Title() string
    Creators() []string
    Created() time.Time
}

其它的一些特性只對特定類型的文化產(chǎn)品才有。和文字排版特性相關(guān)的只有books和magazines,還有只有movies和TV劇集和屏幕分辨率相關(guān)。

type Text interface {
    Pages() int
    Words() int
    PageSize() int
}
type Audio interface {
    Stream() (io.ReadCloser, error)
    RunningTime() time.Duration
    Format() string // e.g., "MP3", "WAV"
}
type Video interface {
    Stream() (io.ReadCloser, error)
    RunningTime() time.Duration
    Format() string // e.g., "MP4", "WMV"
    Resolution() (x, y int)
}

這些接口不止是一種有用的方式來分組相關(guān)的具體類型和表示他們之間的共同特點。我們后面可能會發(fā)現(xiàn)其它的分組。舉例,如果我們發(fā)現(xiàn)我們需要以同樣的方式處理Audio和Video,我們可以定義一個Streamer接口來代表它們之間相同的部分而不必對已經(jīng)存在的類型做改變。

type Streamer interface {
    Stream() (io.ReadCloser, error)
    RunningTime() time.Duration
    Format() string
}

每一個具體類型的組基于它們相同的行為可以表示成一個接口類型。不像基于類的語言,他們一個類實現(xiàn)的接口集合需要進行顯式的定義,在Go語言中我們可以在需要的時候定義一個新的抽象或者特定特點的組,而不需要修改具體類型的定義。當(dāng)具體的類型來自不同的作者時這種方式會特別有用。當(dāng)然也確實沒有必要在具體的類型中指出這些共性。



以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號