天天看點

Golang筆記 4.2 go 接口

1 它是什麼

說背景和地位

摘錄自《go語言程式設計》
接口在Go語言有着至關重要的地位。如果說goroutine和channel 是支撐起Go語言的并發模型的基石,讓Go語言在如今叢集化與多核化的時代成為一道極為亮麗的風景,那麼接口是Go語言整個類型系統的基石,讓Go語言在基礎程式設計哲學的探索上達到前所未有的高度。

Go語言在程式設計哲學上是變革派,而不是改良派。這不是因為Go語言有goroutine和channel,而更重要的是因為Go語言的類型系統,更是因為Go語言的接口。 Go語言的程式設計哲學因為有接口而趨近完美。

Go語言的非侵入式接口,看似隻是做了很小的文法調整,實則影響深遠。

侵入式接口,“侵入式”的主要表現在于實作類需要明确聲明自己實作了某個接口。           

複制

一句話說明

接口提供了一種方式來說明對象的行為:如果誰能搞定這件事,它就可以用在這兒。

接口定義了一組方法(方法集),但是這些方法不包含(實作)代碼:它們沒有被實作(它們是抽象的)。

是以一句話來說,接口是使用方法的抽象。

2 為什麼需要它

接口是使用方法的抽象,使目前程式可以更聚焦在方法的應用,不關心該方法的具體實作。

3 怎麼用

接口指派

接口定義:

type Integer int
func (a Integer) Less(b Integer) bool {
	return a < b
}
func (a *Integer) Add(b Integer) {
	*a += b
}

type LessAdder interface {
	Less(b Integer) bool
	Add(b Integer)
}           

複制

接口指派,将執行個體指派給接口:

var a Integer = 1
var b LessAdder = &a           

複制

接口查詢

var file1 Writer = ...
if file5, ok := file1.(two.IStream); ok {
	...
}           

複制

Writer接口的實作執行個體file1,是否實作了 two.IStream 接口,如果實作了則執行代碼。

類型查詢

在 Go 語言中,還可以更加直截了當地詢問接口指向的對象執行個體的類型。

利用反射也可以進行類型查詢,詳情可參閱reflect.TypeOf()方法。

var v1 interface{} = ...
switch v := v1.(type) {
	case int: // 現在v的類型是int
	case string: // 現在v的類型是string
	...
}           

複制

接口組合

type ReadWriter interface {
	Reader
	Writer
}           

複制

這個接口組合了Reader和Writer兩個接口,它完全等同于如下寫法:

type ReadWriter interface {
	Read(p []byte) (n int, err error)
	Write(p []byte) (n int, err error)
}           

複制

4 示例

典型示例 關注使用,不操心接口實作。來自于《GO示例學》。

// 這裡定義了一個最基本的表示幾何形狀的方法的接口

type geometry interface {
  area() float64
  perim() float64
}           

複制

// 這裡不管正方形或者長方形怎麼去實作自己的接口,但最後使用部分,直接用接口方法就好了。

func measure(g geometry) {
  fmt.Println(g)
  fmt.Println(g.area())
  fmt.Println(g.perim())
}           

複制

5 空接口 Any類型

由于Go語言中任何對象執行個體都滿足空接口interface{},是以interface{}看起來像是可以指向任何對象的 Any 類型,如下:

var v1 interface{} = 1 // 将int類型指派給interface{}
var v2 interface{} = "abc" // 将string類型指派給interface{}
var v3 interface{} = &v2 // 将*interface{}類型指派給interface{}
var v4 interface{} = struct{ X int }{1}
var v5 interface{} = &struct{ X int }{1}           

複制

當函數可以接受任意的對象執行個體時,我們會将其聲明為interface{},最典型的例子是标準庫 fmt 中 PrintXXX 系列的函數,例如:

傳入參數是 可變數量的 任意類型。

func Printf(fmt string, args ...interface{})
func Println(args ...interface{})           

複制

總體來說, 我們剛開始對 interface{} 一無所知,但可以通過接口查詢和類型查詢逐漸了解它。

6 小結

總結,接口是使用方法的抽象,使目前程式可以更聚焦在方法的應用,不關心該方法的具體實作。後續的應用程式在做具體實作時,再去完善具體實作,不會影響之前程式已經定義好的邏輯。

更通俗地來講,接口的定義,就像是設定了一個崗位,描述了崗位的職責;,一些規章可以先根據崗位職責來制定,不關心具體是誰來任職這個崗位。當應用程式開始執行的時候,需要給接口傳入一個執行個體,相當于企業開始營運時再把一個人放到這個崗位。

另外空接口 interface{} 作為 Any 類型也有很廣到應用。

END