概述
Go 中檢測(cè)一個(gè)類型是否實(shí)現(xiàn)了某個(gè)接口,通常分為兩類機(jī)制: 編譯期間 和 運(yùn)行期間。
編譯期間
顧名思義,編譯期間檢測(cè)就是通過靜態(tài)分析來確定類型是否實(shí)現(xiàn)了某個(gè)接口,如果檢測(cè)不通過,則編譯過程報(bào)錯(cuò)并退出。通常將這種方式稱為 接口完整性檢查。
接口完整性檢查
類型未實(shí)現(xiàn)接口
package main
type Person interface {
Name() string
Age() int
}
type Martian struct {
}
func main() {
// 強(qiáng)制類型 Martian 必須實(shí)現(xiàn)接口 Person 的所有方法
var _ Person = (*Martian)(nil)
// 1. 聲明一個(gè) _ 變量 (不使用)
// 2. 把一個(gè) nil 轉(zhuǎn)換為 (*Martian),然后再轉(zhuǎn)換為 Person
// 3. 如果 Martian 沒有實(shí)現(xiàn) Person 的全部方法,則轉(zhuǎn)換失敗,編譯器報(bào)錯(cuò)
}
運(yùn)行代碼
$ go run main.go
# 輸出如下
cannot use (*Martian)(nil) (value of type *Martian) as type Person in variable declaration:
*Martian does not implement Person (missing Age method)
從輸出的結(jié)果中可以看到,Martian 并沒有實(shí)現(xiàn) Person 接口,所以報(bào)錯(cuò)了。下面我們?yōu)?Martian 實(shí)現(xiàn) Person 接口。
類型實(shí)現(xiàn)了接口
package main
import "fmt"
type Person interface {
Name() string
Age() int
}
type Martian struct {
}
// 實(shí)現(xiàn) Name 方法
func (m *Martian) Name() string {
return "martian"
}
// 實(shí)現(xiàn) Age 方法
func (m *Martian) Age() int {
return -1
}
func main() {
// 此時(shí) Martian 已實(shí)現(xiàn)了 Person 的全部方法
var _ Person = (*Martian)(nil)
m := &Martian{}
fmt.Printf("name = %s, age = %d\\n", m.Name(), m.Age())
}
運(yùn)行代碼
$ go run main.go
# 輸出如下
name = martian, age = -1
從輸出的結(jié)果中可以看到,運(yùn)行成功,Martian 已經(jīng)實(shí)現(xiàn)了 Person 接口的全部方法。
運(yùn)行期間
運(yùn)行期間的檢測(cè)方式主要有 類型斷言 和 反射。
類型斷言
類型未實(shí)現(xiàn)接口
package main
import "fmt"
type Person interface {
Name() string
Age() int
}
type Martian struct {
}
func main() {
// 變量必須聲明為 interface 類型
var m interface{}
m = &Martian{}
if v, ok := m.(Person); ok {
fmt.Printf("name = %s, age = %d\\n", v.Name(), v.Age())
} else {
fmt.Println("Martian does not implements Person")
}
}
運(yùn)行代碼
$ go run main.go
# 輸出如下
Martian does not implements Person
下面我們?yōu)?Martian 實(shí)現(xiàn) Person 接口。
類型實(shí)現(xiàn)了接口
package main
import "fmt"
type Person interface {
Name() string
Age() int
}
type Martian struct {
}
func (m *Martian) Name() string {
return "martian"
}
func (m *Martian) Age() int {
return -1
}
func main() {
// 變量必須聲明為 interface 類型
var m interface{}
m = &Martian{}
if v, ok := m.(Person); ok {
fmt.Printf("name = %s, age = %d\\n", v.Name(), v.Age())
}
}
運(yùn)行代碼
$ go run main.go
# 輸出如下
name = martian, age = -1
從輸出的結(jié)果中可以看到,運(yùn)行成功,Martian 已經(jīng)實(shí)現(xiàn)了 Person 接口的全部方法。
反射
通過 reflect 包提供的 API 來判斷類型是否實(shí)現(xiàn)了某個(gè)接口。
類型未實(shí)現(xiàn)接口
package main
import (
"fmt"
"reflect"
)
type Person interface {
Name() string
Age() int
}
type Martian struct {
}
func main() {
// 獲取 Person 類型
p := reflect.TypeOf((*Person)(nil)).Elem()
// 獲取 Martian 結(jié)構(gòu)體指針類型
m := reflect.TypeOf(&Martian{})
// 判斷 Martian 結(jié)構(gòu)體類型是否實(shí)現(xiàn)了 Person 接口
fmt.Println(m.Implements(p))
}
運(yùn)行代碼
$ go run main.go
# 輸出如下
false
下面我們?yōu)?Martian 實(shí)現(xiàn) Person 接口。
類型實(shí)現(xiàn)了接口
package main
import (
"fmt"
"reflect"
)
type Person interface {
Name() string
Age() int
}
type Martian struct {
}
func (m *Martian) Name() string {
return "martian"
}
func (m *Martian) Age() int {
return -1
}
func main() {
// 獲取 Person 類型
p := reflect.TypeOf((*Person)(nil)).Elem()
// 獲取 Martian 結(jié)構(gòu)體指針類型
m := reflect.TypeOf(&Martian{})
// 判斷 Martian 結(jié)構(gòu)體類型是否實(shí)現(xiàn)了 Person 接口
fmt.Println(m.Implements(p))
}
運(yùn)行代碼
$ go run main.go
# 輸出如下
true
小結(jié)
Go 的接口實(shí)現(xiàn)檢測(cè)機(jī)制分為 編譯期間 和 運(yùn)行期間,其中編譯期間的檢測(cè)方式是 接口完整性檢查, 而運(yùn)行期間的檢測(cè)方式有兩種: 類型斷言 和 反射,一般情況盡量使用類型斷言,這樣可以避免反射帶來的性能損耗。文中提到的幾種檢測(cè)方式的代碼語(yǔ)法都比較新 (nan) 奇 (kan) ,讀者可以參考代碼的注釋部分幫助理解。
-
VaR
+關(guān)注
關(guān)注
0文章
39瀏覽量
11754 -
API接口
+關(guān)注
關(guān)注
1文章
115瀏覽量
11278 -
go語(yǔ)言
+關(guān)注
關(guān)注
1文章
159瀏覽量
9848
發(fā)布評(píng)論請(qǐng)先 登錄
HarmonyOS Next原生應(yīng)用開發(fā)-從TS到ArkTS的適配規(guī)則(十)
在三相電能測(cè)量系統(tǒng)實(shí)現(xiàn)電能質(zhì)量分析的參考設(shè)計(jì)包括BOM及層圖
基于LUT的輸入處理的FPGA實(shí)現(xiàn)-應(yīng)用筆記
160MHz帶寬標(biāo)準(zhǔn)無(wú)線信號(hào)測(cè)試儀的IF子系統(tǒng)包括BOM及層圖
電壓三倍器實(shí)現(xiàn)高輸入至輸出升壓比的轉(zhuǎn)換器參考設(shè)計(jì)
簡(jiǎn)易6LoWPAN網(wǎng)狀終端節(jié)點(diǎn)參考設(shè)計(jì)包括BOM及層圖
可實(shí)現(xiàn)兩個(gè)小尺寸集成FET的8V-20V輸入同步降壓轉(zhuǎn)換器
dspic30f5011陷入未知狀態(tài)
Lock體系結(jié)構(gòu)和讀寫鎖機(jī)制解析
#HarmonyOS征文#—HarmonyOS實(shí)現(xiàn)雙擊事件
HarmonyOS實(shí)戰(zhàn)—實(shí)現(xiàn)長(zhǎng)按事件
使用AT89C2051微控制器實(shí)現(xiàn)簡(jiǎn)單溫度計(jì)的設(shè)計(jì)
基本組合邏輯功能雙向管腳的Verilog HDL源代碼
隔離電源PMBus接口的數(shù)字控制器ADP1050數(shù)據(jù)表
如何實(shí)現(xiàn)implements ?
評(píng)論