概述
Go 中檢測一個類型是否實現(xiàn)了某個接口,通常分為兩類機制: 編譯期間
和 運行期間
。
編譯期間
顧名思義,編譯期間檢測就是通過靜態(tài)分析來確定類型是否實現(xiàn)了某個接口,如果檢測不通過,則編譯過程報錯并退出。通常將這種方式稱為 接口完整性檢查
。
接口完整性檢查
類型未實現(xiàn)接口
package main
type Person interface {
Name() string
Age() int
}
type Martian struct {
}
func main() {
// 強制類型 Martian 必須實現(xiàn)接口 Person 的所有方法
var _ Person = (*Martian)(nil)
// 1. 聲明一個 _ 變量 (不使用)
// 2. 把一個 nil 轉(zhuǎn)換為 (*Martian),然后再轉(zhuǎn)換為 Person
// 3. 如果 Martian 沒有實現(xiàn) Person 的全部方法,則轉(zhuǎ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
并沒有實現(xiàn) Person
接口,所以報錯了。下面我們?yōu)?Martian
實現(xiàn) Person
接口。
類型實現(xiàn)了接口
package main
import "fmt"
type Person interface {
Name() string
Age() int
}
type Martian struct {
}
// 實現(xiàn) Name 方法
func (m *Martian) Name() string {
return "martian"
}
// 實現(xiàn) Age 方法
func (m *Martian) Age() int {
return -1
}
func main() {
// 此時 Martian 已實現(xiàn)了 Person 的全部方法
var _ Person = (*Martian)(nil)
m := &Martian{}
fmt.Printf("name = %s, age = %d\\n", m.Name(), m.Age())
}
運行代碼
$ go run main.go
# 輸出如下
name = martian, age = -1
從輸出的結(jié)果中可以看到,運行成功,Martian
已經(jīng)實現(xiàn)了 Person
接口的全部方法。
運行期間
運行期間的檢測方式主要有 類型斷言
和 反射
。
類型斷言
類型未實現(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")
}
}
運行代碼
$ go run main.go
# 輸出如下
Martian does not implements Person
下面我們?yōu)?Martian
實現(xiàn) Person
接口。
類型實現(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())
}
}
運行代碼
$ go run main.go
# 輸出如下
name = martian, age = -1
從輸出的結(jié)果中可以看到,運行成功,Martian
已經(jīng)實現(xiàn)了 Person
接口的全部方法。
反射
通過 reflect
包提供的 API 來判斷類型是否實現(xiàn)了某個接口。
類型未實現(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)體類型是否實現(xiàn)了 Person 接口
fmt.Println(m.Implements(p))
}
運行代碼
$ go run main.go
# 輸出如下
false
下面我們?yōu)?Martian
實現(xiàn) Person
接口。
類型實現(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)體類型是否實現(xiàn)了 Person 接口
fmt.Println(m.Implements(p))
}
運行代碼
$ go run main.go
# 輸出如下
true
小結(jié)
Go 的接口實現(xiàn)檢測機制分為 編譯期間
和 運行期間
,其中編譯期間的檢測方式是 接口完整性檢查
, 而運行期間的檢測方式有兩種: 類型斷言
和 反射
,一般情況盡量使用類型斷言,這樣可以避免反射帶來的性能損耗。文中提到的幾種檢測方式的代碼語法都比較新 (nan) 奇 (kan) ,讀者可以參考代碼的注釋部分幫助理解。
-
VaR
+關(guān)注
關(guān)注
0文章
39瀏覽量
11351 -
API接口
+關(guān)注
關(guān)注
1文章
84瀏覽量
10438 -
go語言
+關(guān)注
關(guān)注
1文章
158瀏覽量
9050
發(fā)布評論請先 登錄
相關(guān)推薦
評論