Golang学习——interface接口学习(二)

栏目: IT技术 · 发布时间: 4年前

内容简介:在在学习接口断言之前,先了解一下类型断言,其实接口断言也是在判断类型。类型断言,通过它可以做到以下几件事情:

Golang接口断言学习

    • 1.if else结构 接口断言

    • 2.switch结构 接口断言

Golang 中,空接口 interface{} 没有定义任何函数,因此 Golang 中所有类型都实现了空接口。当一个函数的形参是 interface{} ,那么在函数中,需要对形参进行断言,从而得到它的真实类型。

一.类型断言

在学习接口断言之前,先了解一下类型断言,其实接口断言也是在判断类型。

类型断言,通过它可以做到以下几件事情:

  1. 检查 i 是否为 nil
  2. 检查 i 存储的值是否为 某个类型

通常有两种方式:

第一种:

t := i.(T) 复制代码

这个表达式可以断言一个接口对象 i 里不是 nil ,并且接口对象 i 存储的值的类型是 T ,如果断言成功,就会返回值给 t ,如果断言失败,就会触发 panic

t := i.(T) 常用于 switch 结构。

第二种:

t, ok:= i.(T) 复制代码

这个表达式也是可以断言一个接口对象 t 里不是 nil ,并且接口对象 t 存储的值的类型是 T ;

如果断言成功,就会返回其类型给 t ,并且此时 ok 的值 为 true ,表示断言成功。

如果接口值的类型,并不是我们所断言的 T ,就会断言失败,但和第一种表达式不同的事,这个不会触发 panic ,而是将 ok 的值设为 false ,表示断言失败,此时 tT 的零值。

t, ok:= i.(T) 常用于 if else 结构。

二.接口断言

1.if else结构 接口断言

t, ok := i.(T) 断言在上一小节已经介绍过了,本小节,我们通过实战加深下理解。

我们先创建一个 Shape 形状接口,两个结构体。

// 定义接口
type Shape interface {
 perimeter() float64 // 返回形状的周长
 area() float64      // 返回形状的面积
}

// 定义结构体
type Circle struct {
 radius float64
}

type Triangle struct {
 a, b, c float64
}
复制代码

其中, Shape 接口有两个方法,分别是求形状的周长和面积。

两个结构体分别定义了自己独有的属性:

  • Circle (圆),定义了半径
  • Triangle (三角形),定义了三条边

接下来,我们实现 Shape 接口中的方法:

// 圆结构体 实现接口方法
func (c Circle) perimeter() float64 {
 return c.radius * math.Pi * 2
}

func (c Circle) area() float64 {
 return math.Pow(c.radius, 2) * math.Pi
}

// 三角形结构体 实现接口方法
func (t Triangle) perimeter() float64 {
 return t.a + t.b + t.c
}
func (t Triangle) area() float64 {
 p := t.perimeter() / 2
 return math.Sqrt(p * (p - t.a) * (p - t.b) * (p - t.c))
}
复制代码

其中三角形的面积计算使用了 海伦公式

接下来我们封装一个接口断言函数:

// 定义接口断言函数
func getInterfaceType(s Shape) {
 if ins, ok := s.(Triangle); ok {
  fmt.Println("是三角形,三边分别为:", ins.a, ins.b, ins.c)
 } else if ins, ok := s.(Circle); ok {
  fmt.Println("是圆形,半径为;", ins.radius)
 } else if ins, ok := s.(*Circle); ok {
  fmt.Printf("是圆形结构体指针,类型为:%T,存储的地址为:%p,指针自身的地址为:%p\n", ins, &ins, ins)
 } else {
  fmt.Println("无法判断类型...")
 }
}
复制代码

该函数中不仅判断了值传递的类型,也判断了引用传递(指针类型)的类型。因为 Struct 是值类型,所以我们加入引用类型,使练习更严谨一点。

接下来开始初始化结构体:

// 初始化一个圆结构体
c1 := Circle{radius: 10}
fmt.Println("==================圆结构体:==================")
fmt.Println("圆的周长为:", c1.perimeter())
fmt.Println("圆的面积为:", c1.area())

// 初始化一个三角形结构体
t1 := Triangle{
 a: 3,
 b: 4,
 c: 5,
}
fmt.Println("================三角形结构体:=================")
fmt.Println("三角形的周长为:", t1.perimeter())
fmt.Println("三角形的面积为:", t1.area())

// 初始化一个圆形结构体指针
var c2 *Circle = &Circle{radius: 5}
fmt.Println("================圆形结构体指针:===============")
fmt.Println("圆的周长为:", c2.perimeter())
fmt.Println("圆的面积为:", c2.area())
复制代码

输出:

==================圆结构体:==================
圆的周长为: 62.83185307179586
圆的面积为: 314.1592653589793
================三角形结构体:=================
三角形的周长为: 12
三角形的面积为: 6
================圆形结构体指针:===============
圆的周长为: 31.41592653589793
圆的面积为: 78.53981633974483
复制代码

可以看到,以上结构体都实现了 Shape 接口, 接下来开始进行接口断言:

fmt.Println("==============t, ok:= i.(T) 开始接口断言====================")
getInterfaceType(c1) // 判断该接口是否为 圆形结构体类型
getInterfaceType(t1) // 判断该接口是否为 圆形结构体类型
getInterfaceType(c2) // 判断该接口是否为 圆形结构体指针类型
复制代码

输出:

==============t, ok:= i.(T) 开始接口断言===================
是圆形,半径为; 10
是三角形,三边分别为: 3 4 5
是圆形结构体指针,类型为:*main.Circle,存储的地址为:0xc000006030,指针自身的地
址为:0xc0000140e0
复制代码

可以看到,我们的接口断言奏效了,并且输出了对应逻辑的结果。

2.switch结构 接口断言

断言其实还有另一种形式,就是用在利用 switch 语句判断接口的类型。

每一个 case 会被顺序地考虑。当命中一个 case 时,就会执行 case 中的语句。

因此 case 语句的顺序是很重要的,因为很有可能会有多个 case 匹配的情况。

我们再封装一个 switch 逻辑的接口断言函数,逻辑和之前的一模一样,只是条件语句换成了 switch....case

// 定义接口断言函数,使用 switch
func getInterfaceTypeSwitch(s Shape) {
 switch ins := s.(type) { // 首字母小写的 type
 case Circle:
  fmt.Println("是圆形,半径为;", ins.radius)
 case Triangle:
  fmt.Println("是三角形,三边分别为:", ins.a, ins.b, ins.c)
 case *Circle:
  fmt.Printf("是圆形结构体指针,类型为:%T,存储的地址为:%p,指针自身的地址为:%p\n", ins, &ins, ins)
 default:
  fmt.Println("无法判断类型...")
 }
}
复制代码

接下来测试封装的函数:

fmt.Println("==============t := i.(type) 开始接口断言====================")
getInterfaceTypeSwitch(c1) // 判断该接口是否为 圆形结构体类型
getInterfaceTypeSwitch(t1) // 判断该接口是否为 圆形结构体类型
getInterfaceTypeSwitch(c2) // 判断该接口是否为 圆形结构体指针类型
复制代码

输出:

==============t := i.(type) 开始接口断言====================
是圆形,半径为; 10
是三角形,三边分别为: 3 4 5
是圆形结构体指针,类型为:*main.Circle,存储的地址为:0xc000006038,指针自身的地
址为:0xc0000140e0
复制代码

可以看到, switch 断言的逻辑也正常输出了。

总结一下,今天主要记录了接口如何断言的,通常有两种方式:

  1. 方式一: t, ok:= i.(T)
  • t
    ok
    true
    
  • ok
    false
    t
    T
    
  • 通常用于 if else 结构
  1. 方式二: t := i.(T)
  • i
    nil
    i
    T
    
  • 如果断言成功,就会返回值给 t ,如果断言失败,就会触发 panic
  • 通常用于 switch 结构

本文使用 mdnice 排版


以上所述就是小编给大家介绍的《Golang学习——interface接口学习(二)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

如何把事情做到最好

如何把事情做到最好

乔治·伦纳德 / 张乐 / 中国青年出版社 / 2014-2 / 29.90元

•改变全球9800万人的人生指导书 •全美第一本系统阐述学习与成功之道的经典著作 •长期盘踞全美畅销书榜单 •21年后,这本传奇之书终于在中国震撼上市 •把事情做到最好,第一不强求天赋,第二不介意起步的早晚,你要做的就是“起步走”并“不停地走” 《如何把事情做到最好》出 版于1992年,经久不衰,经过一代又一代的读者口碑相传后,畅销至今。作者以其独特的视角告诉人们,如......一起来看看 《如何把事情做到最好》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

SHA 加密
SHA 加密

SHA 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换