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

Golang接口断言学习

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

一.类型断言

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

类型断言,经过它能够作到如下几件事情:测试

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

一般有两种方式:
第一种:url

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

这个表达式能够断言一个接口对象i里不是 nil,而且接口对象i存储的值的类型是 T,若是断言成功,就会返回值给t,若是断言失败,就会触发 panicspa

t := i.(T) 经常使用于 switch 结构。指针

第二种:code

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,表示断言成功
  • 断言失败, okfalsetT的零值
  • 一般用于 if else结构
  1. 方式二: t := i.(T)
  • 断言一个接口对象 i里不是 nil,而且接口对象 i存储的值的类型是 T
  • 若是断言成功,就会返回值给 t,若是断言失败,就会触发 panic
  • 一般用于 switch结构

本文使用 mdnice 排版

相关文章
相关标签/搜索