接口类型探测:类型断言

接口实例中存储了实现接口的类型实例,类型的实例有两种:值类型实例和指针类型实例。在程序运行过程中,接口实例存储的实例类型可能会动态改变。例如:

// ins是接口实例
var ins Shaper// ins存储值类型的实例
ins = c1// 一段时间后...
...// ins存储指针类型的实例,存储的类型发生改变
ins = c2// 一段时间后...// ins可能存储另一个类型实例
ins = s1

所以,需要一种探测接口实例所存储的是值类型还是指针类型。

探测的方法是:ins.(Type)ins.(*Type)。它们有两个返回值,第二个返回值是ok返回值,布尔类型,第一个返回值是探测出的类型。也可以只有一个返回值:探测出的类型。

// 如果ins保存的是值类型的Type,则输出
if t, ok := ins.(Type); ok {fmt.Printf("%T\n", v)
}// 如果ins保存的是指针类型的*Type,则输出
if t, ok := ins.(*Type); ok {fmt.Printf("%T\n", v)
}// 一个返回值的探测
t := ins.(Type)
t := ins.(*Type)

以下是一个例子:

package mainimport "fmt"// Shaper 接口类型
type Shaper interface {Area() float64
}// Square struct类型
type Square struct {length float64
}// Square类型实现Shaper中的方法Area()
func (s Square) Area() float64 {return s.length * s.length
}func main() {var ins1, ins2 Shaper// 指针类型的实例s1 := new(Square)s1.length = 3.0ins1 = s1if v, ok := ins1.(*Square); ok {fmt.Printf("ins1: %T\n", v)}// 值类型的实例s2 := Square{4.0}ins2 = s2if v, ok := ins2.(Square); ok {fmt.Printf("ins2: %T\n", v)}
}

上面两个Printf都会输出,因为它们的类型判断都返回true。如果将ins2.(Square)改为ins2.(*Square),第二个Printf将不会输出,因为ins2它保存的是值类型的实例。

以下是输出结果:

ins1: *main.Square
ins2: main.Square

特别需要注意的是,ins必须明确是接口实例。例如,以下前两种声明是有效的,第三种推断类型是错误的,因为它可能是接口实例,也可能是类型的实例副本。

var ins Shaper     // 正确
ins := Shaper(s1)  // 正确
ins := s1          // 错误

当ins不能确定是接口实例时,用它来进行测试,例如ins.(Square)将会报错:

invalid type assertion:ins.(Square) (non-interface type (type of ins) on left)

它说明了左边的ins是非接口类型(non-interface type)。

另一方面,通过接口类型断言(ins.(Type)),如果Type是一个接口类型,就可以判断接口实例ins中所保存的类型是否也实现了Type接口。例如:

var r io.Read
tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
if err != nil {return nil, err
}
r = ttyvar w io.Writer
w = r.(io.Writer)

上面的r是io.Read接口的一个实例变量,它里面保存的是tty和它的类型,即(tty, *os.File),然后断言r的类型,探测它里面的类型*File是否也实现了io.Writer接口,如果实现了,则保存到io.Writer接口的实例变量w中,这样w实例也将保存(tty,*os.File)

由于任意内容都实现了空接口,所以,总是可以把一个接口实例无需通过任何断言地赋值给一个空接口实例:

var empty interface{}
empty = w

现在empty也保存了(tty,*os.File)

type Switch结构

switch流程控制结构还可以用来探测接口实例保存的类型。这种结构称为type-switch

用法如下:

switch v := ins.(type) {
case *Square:fmt.Printf("Type Square %T\n", v)
case *Circle:fmt.Printf("Type Circle %T\n", v)
case nil:fmt.Println("nil value: nothing to check?")
default:fmt.Printf("Unexpected type %T", v)
}

其中ins.(type)中的小写type是固定的词语。

以下是一个使用示例:

package mainimport ("fmt"
)// Shaper 接口类型
type Shaper interface {Area() float64
}// Circle struct类型
type Circle struct {radius float64
}// Circle类型实现Shaper中的方法Area()
func (c *Circle) Area() float64 {return 3.14 * c.radius * c.radius
}// Square struct类型
type Square struct {length float64
}// Square类型实现Shaper中的方法Area()
func (s Square) Area() float64 {return s.length * s.length
}func main() {s1 := &Square{3.3}whichType(s1)s2 := Square{3.4}whichType(s2)c1 := new(Circle)c1.radius = 2.3whichType(c1)
}func whichType(n Shaper) {switch v := n.(type) {case *Square:fmt.Printf("Type Square %T\n", v)case Square:fmt.Printf("Type Square %T\n", v)case *Circle:fmt.Printf("Type Circle %T\n", v)case nil:fmt.Println("nil value: nothing to check?")default:fmt.Printf("Unexpected type %T", v)}
}

上面的type-switch中,之所以没有加上case Circle,是因为Circle只实现了指针类型的receiver,根据Method Set对接口的实现规则,只有指针类型的Circle示例才算是实现了接口Shaper,所以将值类型的示例case Circle放进type-switch是错误的。

转载于:https://www.cnblogs.com/f-ck-need-u/p/9893347.html

Go基础系列:接口类型断言和type-switch相关推荐

  1. 泛型技巧系列:类型字典和Type Traits

    注意:未经许可,本系列禁止转载. 本文所介绍的技巧,是我在研究泛型开发不久就发现并成功运用的技巧.这个技巧是突破.NET泛型限制,达到"看上去很美"境界的法宝.当然本方法也存在重大 ...

  2. JMeter基础系列:接口响应时间

    1 简介 插件文档:https://jmeter-plugins.org/wiki/Start/ 插件管理器安装:https://blog.csdn.net/Xin_101/article/detai ...

  3. winform point数组带数值_带你学够浪:Go语言基础系列 - 8分钟学复合类型

    对于一般的语言使用者来说 ,20% 的语言特性就能够满足 80% 的使用需求,剩下在使用中掌握.基于这一理论,Go 基础系列的文章不会刻意追求面面俱到,但该有知识点都会覆盖,目的是带你快跑赶上 Gol ...

  4. typescript利用接口类型声明变量_TypeScript入门指南(基础篇)

       戳蓝字「前端技术优选」关注我们哦! 作者:慕晨同学 原文地址:https://github.com/USTB-musion/fee-skills/issues/19 写在前面 ts是拥有类型系统 ...

  5. TS基础1(类型定义、接口)-学习笔记

    文章目录 TS基础1(类型定义.接口)-学习笔记 什么是TS TS基础1(类型定义.接口)-学习笔记 什么是TS //ts用法var n:number = 10;let str:string = '1 ...

  6. TypeScript基础入门 - 接口 - 可索引的类型

    转载地址 TypeScript基础入门 - 接口 - 可索引的类型 项目实践仓库 https://github.com/durban89/typescript_demo.git tag: 1.0.11 ...

  7. 夯实Java基础系列6:一文搞懂抽象类和接口,从基础到面试题,揭秘其本质区别!

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  8. 2021-12-15 网工基础(十一) VLAN的基本原理、接口类型、Access、Trunk

    VLAN基础 二 VLAN的基本原理 1 以太网二层接口类型 Access接口 交换机上常用来连接用户PC.服务器等终端设备的接口.Access接口所连接的这些设备的网卡往往只收发无标记帧.Acces ...

  9. JVM基础系列第10讲:垃圾回收的几种类型

    我们经常会听到许多垃圾回收的术语,例如:Minor GC.Major GC.Young GC.Old GC.Full GC.Stop-The-World 等.但这些 GC 术语到底指的是什么,它们之间 ...

  10. 华为ax3怎么接光纤sc接口_光纤收发器接口类型、连接、指示灯说明及故障症断...

    光纤收发器有多种不同的分类,而实际使用中大多注意的是按光纤接头不同而区分的类别:SC接头光纤收发器和FC/ST接头光纤收发器. 各种光纤接口类型介绍 光纤接头 FC 圆型带螺纹(配线架上用的最多) S ...

最新文章

  1. PHP+socket+SMTP、POP3协议发送、接收邮件
  2. 聊聊Service Mesh:linkerd
  3. 艾伟_转载:C# Design Patterns (3) - Decorator
  4. php新闻模块,新闻模块实现
  5. JAVA-接口和抽象类的区别
  6. 【代码示例】springboot使用drools实现动态规划
  7. Windows域的管理
  8. python函数可变参数_python中函数的可变参数
  9. VLAN设置实例全程解读
  10. thymeleaf随机数_SpringBoot2.0实现静态资源版本控制
  11. 找工作经验之——准备工作
  12. android开发实践之1:安装部署环境设置
  13. android之去掉actionbar
  14. lightoj1213推公式
  15. 常见排序算法之归并排序
  16. 数学分析:集合理论----习题
  17. 2019年全国各类型POI数据
  18. 用户行为分析的指标体系
  19. MATLAB数字图像处理小系统 【带GUI界面,源码实现】
  20. 数据库索引的分类,类型,索引的优缺点,索引的优化

热门文章

  1. 北漂九年 ,雷军终于买房了:壕掷52亿元
  2. R语言中文社区2018年终文章整理(类型篇)
  3. Django2.1配置xadmin2.0
  4. UVA11107 Life Forms --- 后缀数组
  5. 关于index 索引
  6. WebApi2官网学习记录---Media Formatters
  7. 【原创】《算法导论》链表一章带星习题试解——附C语言实现
  8. 详解Nginx + Tomcat 反向代理 如何在高效的在一台服务器部署多个站点
  9. httpd-2.2部署Discuz!论坛系统、wordpress博客系统和phpMyAdmin程序
  10. 手摸手带你入门ionic3(六):界面跳转