概述
Go 中检测一个类型是否实现了某个接口,通常分为两类机制: 编译期间 和 运行期间。
编译期间
顾名思义,编译期间检测就是通过静态分析来确定类型是否实现了某个接口,如果检测不通过,则编译过程报错并退出。通常将这种方式称为 接口完整性检查。
接口完整性检查
类型未实现接口
package main
type Person interface {
Name() string
Age() int
}
type Martian struct {
}
func main() {
// 强制类型 Martian 必须实现接口 Person 的所有方法
var _ Person = (*Martian)(nil)
// 1. 声明一个 _ 变量 (不使用)
// 2. 把一个 nil 转换为 (*Martian),然后再转换为 Person
// 3. 如果 Martian 没有实现 Person 的全部方法,则转换失败,编译器报错
}
运行代码
$ 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)
从输出的结果中可以看到,Martian 并没有实现 Person 接口,所以报错了。下面我们为 Martian 实现 Person 接口。
类型实现了接口
package main
import "fmt"
type Person interface {
Name() string
Age() int
}
type Martian struct {
}
// 实现 Name 方法
func (m *Martian) Name() string {
return "martian"
}
// 实现 Age 方法
func (m *Martian) Age() int {
return -1
}
func main() {
// 此时 Martian 已实现了 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
从输出的结果中可以看到,运行成功,Martian 已经实现了 Person 接口的全部方法。
运行期间
运行期间的检测方式主要有 类型断言 和 反射。
类型断言
类型未实现接口
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
下面我们为 Martian 实现 Person 接口。
类型实现了接口
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
从输出的结果中可以看到,运行成功,Martian 已经实现了 Person 接口的全部方法。
反射
通过 reflect 包提供的 API 来判断类型是否实现了某个接口。
类型未实现接口
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 结构体指针类型
m := reflect.TypeOf(&Martian{})
// 判断 Martian 结构体类型是否实现了 Person 接口
fmt.Println(m.Implements(p))
}
运行代码
$ go run main.go
# 输出如下
false
下面我们为 Martian 实现 Person 接口。
类型实现了接口
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 结构体指针类型
m := reflect.TypeOf(&Martian{})
// 判断 Martian 结构体类型是否实现了 Person 接口
fmt.Println(m.Implements(p))
}
运行代码
$ go run main.go
# 输出如下
true
小结
Go 的接口实现检测机制分为 编译期间 和 运行期间,其中编译期间的检测方式是 接口完整性检查, 而运行期间的检测方式有两种: 类型断言 和 反射,一般情况尽量使用类型断言,这样可以避免反射带来的性能损耗。文中提到的几种检测方式的代码语法都比较新 (nan) 奇 (kan) ,读者可以参考代码的注释部分帮助理解。
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。
举报投诉
-
VaR
+关注
关注
0文章
39浏览量
11757 -
API接口
+关注
关注
1文章
115浏览量
11291 -
go语言
+关注
关注
1文章
161浏览量
9857
发布评论请先 登录
相关推荐
热点推荐
HarmonyOS Next原生应用开发-从TS到ArkTS的适配规则(十)
implements
规则:arkts-implements-only-iface
级别:错误
ArkTS不允许类被implements,只有接口可以被implements。
Type
发表于 07-29 16:02
在三相电能测量系统实现电能质量分析的参考设计包括BOM及层图
描述The TIDM-THDREADING reference design implements power quality analysis in a three-phase energy
发表于 09-10 09:02
基于LUT的输入处理的FPGA实现-应用笔记
table (LUT). It implements a piecewise first-order linear approximation of a nonlinear function.
发表于 09-14 21:32
160MHz带宽标准无线信号测试仪的IF子系统包括BOM及层图
描述This reference design implements an IF subsystem for a standard wireless signal tester
发表于 09-18 09:05
电压三倍器实现高输入至输出升压比的转换器参考设计
描述This boost converter implements a voltage tripler which allows a high input-to-output boost
发表于 09-19 09:14
简易6LoWPAN网状终端节点参考设计包括BOM及层图
描述This reference design implements a simple RF mesh network end node for smart meter Advanced
发表于 10-26 10:07
可实现两个小尺寸集成FET的8V-20V输入同步降压转换器
描述The PMP11225 reference design implements two small-footprint integrated FET synchronous buck
发表于 12-06 11:51
dspic30f5011陷入未知状态
嗨,AllI有一个非常困难的问题:(经过几天的正常工作,DSPIC30F5011卡在一个未知的状态。只有重置可以释放它。两个提示:1。SW实现16秒看门狗,在这个问题STATE2中似乎没有激活。SW
发表于 05-07 12:26
Lock体系结构和读写锁机制解析
接口之一,规定了资源锁使用的几个基础方法。ReentrantLock类实现Lock接口的可重入锁,即线程如果获得当前实例的锁,并进入任务方法,在线程没有释放锁的状态下,可以再次进入任务方法,特点:互斥
发表于 01-05 17:53
#HarmonyOS征文#—HarmonyOS实现双击事件
1. 双击事件双击事件和单击事件有些类似,也有四种实现的方法1.通过id找到组件。 2.给按钮组件设置双击事件。 3.本类实现DoubleClickedListener接口重写。 4.重写
发表于 07-28 10:49
HarmonyOS实战—实现长按事件
实现案例:长按按钮修改文本内容新建项目:ListenerApplication3ability_main MainAbilitySlicepackage
发表于 08-12 11:44
使用AT89C2051微控制器实现简单温度计的设计
The system presented in this application note implements a simple digital thermometerthat includes
发表于 06-27 11:34
•75次下载
基本组合逻辑功能双向管脚的Verilog HDL源代码
电子发烧友网核心提示: 本例程是Verilog HDL源代码:关于基本组合逻辑功能中双向管脚的功能实现源代码。 Verilog HDL: Bidirectional Pin This example implements a clocked bidirectional p
发表于 10-15 11:28
•1863次阅读
隔离电源PMBus接口的数字控制器ADP1050数据表
efficiency dc-to-dc power conversion. This controller implements voltage mode control with high speed
发表于 10-26 11:39
•5次下载
如何实现implements ?
评论