内容简介:在在学习接口断言之前,先了解一下类型断言,其实接口断言也是在判断类型。类型断言,通过它可以做到以下几件事情:
Golang接口断言学习
-
-
1.if else结构 接口断言
-
2.switch结构 接口断言
-
在 Golang
中,空接口 interface{}
没有定义任何函数,因此 Golang
中所有类型都实现了空接口。当一个函数的形参是 interface{}
,那么在函数中,需要对形参进行断言,从而得到它的真实类型。
一.类型断言
在学习接口断言之前,先了解一下类型断言,其实接口断言也是在判断类型。
类型断言,通过它可以做到以下几件事情:
-
检查 i 是否为
nil
-
检查 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
,表示断言失败,此时 t
为 T
的零值。
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
断言的逻辑也正常输出了。
总结一下,今天主要记录了接口如何断言的,通常有两种方式:
-
方式一:
t, ok:= i.(T)
-
t ok true
-
ok false t T
-
通常用于
if else
结构
-
方式二:
t := i.(T)
-
i nil i T
-
如果断言成功,就会返回值给
t
,如果断言失败,就会触发panic
-
通常用于
switch
结构
本文使用 mdnice 排版
以上所述就是小编给大家介绍的《Golang学习——interface接口学习(二)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Golang 学习笔记七 接口
- Golang学习笔记 方法和接口
- Go 语言学习5 - 面向接口
- Golang学习笔记之接口(interface)
- Golang 学习笔记三 接口、错误异常
- Golang 学习笔记四 结构体 接口
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。