Golang空接口与类型断言的实现

目录
  • 空接口
    • 定义
    • 使用场景
  • 空接口几个要注意的坑
  • 类型断言
    • Go语言中类型断言的两种语法
    • 类型断言配合 switch 使用

空接口

定义

空接口是特殊形式的接口类型,普通的接口都有方法,而空接口没有定义任何方法口,也因此,我们可以说所有类型都至少实现了空接口。

type test interface {
}

每一个接口都包含两个属性,一个是值,一个是类型。

var i interface{}
fmt.Printf("类型:%T----值:%v\n", i, i) //类型:<nil>----值:<nil>

可见对于空接口来说,这两者都是 nil

使用场景

第一,通常我们会直接使用 interface{} 作为类型声明一个实例,而这个实例可以承载任意类型的值。

func main() {
	var i interface{}

	i = 100
	fmt.Println(i) //100

	i = "yif"
	fmt.Println(i) //yif

	i = 3.14
	fmt.Println(i) //3.14

	i = false
	fmt.Println(i) //false
}

第二,如果想让你的函数可以接收任意类型的值 ,也可以使用空接口。如下代码都正常打印:

func main() {
	i := 100
	s := "yif"
	f := 3.14

	test(i)
	test(s)
	test(f)
}

func test(i interface{}) {
	fmt.Println(i)
}

上面写法有点麻烦,可以使用可变参数的函数。如下:

func main() {
	i := 100
	s := "yif"
	f := 3.14

	test(i, s, f)
}

func test(res ...interface{}) {
	fmt.Println(res) //res是切片
	for k, v := range res {
		fmt.Println(k, v)
	}
}

结果:

D:\workspace\go\src\test>go run main.go
[100 yif 3.14]
0 100
1 yif
2 3.14

第三,你也定义一个可以接收任意类型的 array、slice、map、strcut,例如这边定义一个切片

func main() {
	sli := make([]interface{}, 4)
	sli[0] = 100
	sli[1] = "yif"
	sli[2] = []int{1, 2, 3}
	sli[3] = [...]int{5, 6, 7}
	fmt.Println(sli)
	for k, v := range sli {
		fmt.Println(k, v)
	}
}

结果:

D:\workspace\go\src\test>go run main.go
[100 yif [1 2 3] [5 6 7]]
0 100
1 yif
2 [1 2 3]
3 [5 6 7]

空接口几个要注意的坑

**第一,**空接口可以承载任意值,但不代表任意类型就可以承接空接口类型的值

空接口类型可以保存任何值,也可以从空接口中取出原值。

但要是你把一个空接口类型的对象,再赋值给一个固定类型(比如 int, string等类型)的对象赋值,是会报错的。

var i interface{} = 100
var t int = i // cannot use i (type interface {}) as type int in assignment: need type assertion

但是你使用短变量声明,是可以的:

var i interface{} = 100
t := i
fmt.Println(t) //100

因为编译器会根据等号右边的值来推导变量的类型完成初始化。

**第二:**当空接口承载数组和切片后,该对象无法再进行切片

sli := []int{1, 2, 3, 4}
var i interface{}
i = sli
fmt.Println(i[1:2]) //cannot slice i (type interface {})

类型断言

类型断言(Type Assertion)是一个使用在接口值上的操作,用于检查接口类型变量所持有的值是否实现了期望的接口或者具体的类型

类型断言,仅能对静态类型为空接口(interface{})的对象进行断言,否则会抛出错误

Go语言中类型断言的两种语法

在Go语言中类型断言的第一种语法格式如下:

t := i.(T)

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

func main() {
	var i interface{} = 100
	t := i.(int)
	fmt.Println(t) //100

	fmt.Println("------------------------------------")

	s := i.(string)
	fmt.Println(s)
}

结果【执行第二次断言的时候失败了,并且触发了 panic】:

D:\workspace\go\src\test>go run main.go
100
------------------------------------
panic: interface conversion: interface {} is int, not string

goroutine 1 [running]:
main.main()
        D:/workspace/go/src/test/main.go:32 +0x10e
exit status 2

如果要断言的接口值是 nil,那我们来看看也是不是也如预期一样会触发panic

var i interface{}
var _ = i.(interface{})

结果:

D:\workspace\go\src\test>go run main.go
panic: interface conversion: interface is nil, not interface {}

goroutine 1 [running]:
main.main()
        D:/workspace/go/src/test/main.go:27 +0x34
exit status 2

在Go语言中类型断言的另一种语法格式如下:

t, ok:= i.(T)

和上面一样,这个表达式也是可以断言一个接口对象(i)里不是 nil,并且接口对象(i)存储的值的类型是 T,如果断言成功,就会返回其类型给 t,并且此时 ok 的值 为 true,表示断言成功。

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

func main() {
    var i interface{} = 10
    t1, ok := i.(int)
    fmt.Printf("%d-%t\n", t1, ok)

    fmt.Println("=====分隔线1=====")

    t2, ok := i.(string)
    fmt.Printf("%s-%t\n", t2, ok)

    fmt.Println("=====分隔线2=====")

    var k interface{} // nil
    t3, ok := k.(interface{})
    fmt.Println(t3, "-", ok)

    fmt.Println("=====分隔线3=====")
    k = 10
    t4, ok := k.(interface{})
    fmt.Printf("%d-%t\n", t4, ok)

    t5, ok := k.(int)
    fmt.Printf("%d-%t\n", t5, ok)
}

结果【运行后输出如下,可以发现在执行第二次断言的时候,虽然失败了,但并没有触发了 panic】:

D:\workspace\go\src\test>go run main.go
10-true
=====分隔线1=====
-false
=====分隔线2=====
<nil> - false
=====分隔线3=====
10-true
10-true

上面这段输出,你要注意的是第二个断言的输出在-false 之前并不是有没有输出任何 t2 的值,而是由于断言失败,所以 t2 得到的是 string 的零值也是 "" ,它是零长度的,所以你看不到其输出。

类型断言配合 switch 使用

如果需要区分多种类型,可以使用 type switch 断言。

func main() {
	test(100)
	test("yif")
	test(3.14)

	var i interface{} //nil
	test(i)

	test(nil)
}

func test(i interface{}) {
	switch r := i.(type) {
	case int:
		fmt.Println(r, "是int型")
	case string:
		fmt.Println(r, "是字符串")
	case nil:
		fmt.Println(r, "是nil")
	default:
		fmt.Println("没有结果!")
	}
}

结果:

D:\workspace\go\src\test>go run main.go
100 是int型
yif 是字符串
没有结果!
<nil> 是nil
<nil> 是nil

到此这篇关于Golang空接口与类型断言的实现的文章就介绍到这了,更多相关Golang空接口与类型断言内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 浅谈golang类型断言,失败类型断言返回值问题

    失败的类型断言,返回的值为最近断言类型的零值 代码入下: func main() { var data interface{} = "ehoo" if res, ok := data.(int); ok { fmt.Printf("int res:%d\n", res) } else if res, ok := data.(bool); ok { fmt.Printf("bool res:%b\n", res) } else { fmt.Prin

  • golang中的空接口使用详解

    1.空接口 Golang 中的接口可以不定义任何方法,没有定义任何方法的接口就是空接口.空接口表示,没有任何约束,因此任何类型变量都可以实现空接口.空接口在实际项目中用的是非常多的,用空接口可以表示任意数据类型 func main() { // 定义一个空接口 x, x 变量可以接收任意的数据类型 var x interface{} s := "你好 golang" x = s fmt.Printf("type:%T value:%v\n", x, x) i :=

  • golang强制类型转换和类型断言

    目录 1.强制类型转换 2.类型断言 1.强制类型转换 golang是强类型语言,但是和c++,Java不太一样的是,go中没有隐式类型转换,go中的类型转换只有:强制类型转换和断言 在java中: public static void main(String[] args){ int a = 1; double b = 1.0; System.out.println(a * b); } 在java中这样是没有问题,编译器隐式的把a向上转为double类型 但是在go中是会报错的: 需要进行强制

  • Golang空接口与类型断言的实现

    目录 空接口 定义 使用场景 空接口几个要注意的坑 类型断言 Go语言中类型断言的两种语法 类型断言配合 switch 使用 空接口 定义 空接口是特殊形式的接口类型,普通的接口都有方法,而空接口没有定义任何方法口,也因此,我们可以说所有类型都至少实现了空接口. type test interface { } 每一个接口都包含两个属性,一个是值,一个是类型. var i interface{} fmt.Printf("类型:%T----值:%v\n", i, i) //类型:<n

  • Go 语言中的空接口(推荐)

    在自己学习 Golang 的这段时间里,我写了详细的学习笔记放在我的个人微信公众号 <Go编程时光>,对于 Go 语言,我也算是个初学者,因此写的东西应该会比较适合刚接触的同学,如果你也是刚学习 Go 语言,不防关注一下,一起学习,一起成长. 我的在线博客:http://golang.iswbm.com 我的 Github:github.com/iswbm/GolangCodingTime 1. 什么是空接口? 空接口是特殊形式的接口类型,普通的接口都有方法,而空接口没有定义任何方法口,也因此

  • GO语言类型转换和类型断言实例分析

    本文实例讲述了GO语言类型转换和类型断言的用法.分享给大家供大家参考.具体分析如下: 由于Go语言不允许隐式类型转换.而类型转换和类型断言的本质,就是把一个类型转换到另一个类型. 一.类型转换 (1).语法:<结果类型> := <目标类型> ( <表达式> ) (2).类型转换是用来在不同但相互兼容的类型之间的相互转换的方式,所以,当类型不兼容的时候,是无法转换的.如下: 复制代码 代码如下: func test4() {     var var1 int = 7   

  • Golang中的自定义类型之间的转换的实现(type conversion)

    这里不讨论数值与字符串之间.或者整型与浮点型之间的转换.这里要讨论的是自定义类型之间的转换,这个转换与其他语言都不一样,而且在go的源码中也被大量使用. 这里列举两个实用的例子. 转换成实现了某个(些)接口的自定义类型 比如:sort包里面的IntSlice,是一个[]int的自定义类型,并且实现了sort.Interface接口,如下所示: type IntSlice []int // 实现sort.Interface接口的方法 func (p IntSlice) Len() int { re

  • GO语言类型查询类型断言示例解析

    目录 类型查询 1.comma-ok断言 2. switch测试 类型断言 类型查询 我们知道interface的变量里面可以存储任意类型的数值(该类型实现了interface).那么我们怎么反向知道这个变量里面实际保存了的是哪个类型的对象呢?目前常用的有两种方法: comma-ok断言 switch测试 1.comma-ok断言 Go语言里面有一个语法,可以直接判断是否是该类型的变量: value, ok = element.(T),这里value就是变量的值,ok是一个bool类型,elem

  • TypeScript函数和类型断言实例详解

    目录 开始 断言 非空断言 类型断言 尖括号 as 确定赋值断言 类型守卫 trpeof in 函数 可选参数 默认值参数 函数重载 结束 开始 现在要加速学习了,大佬们有没有内推,给个推荐 会vue2/vue3 + ts 断言 非空断言 非空断言就是确定这个变量不是null或者undefined,就是把null或者undefined从他的类型中排除 function demo(message:string|undefined|null) { const str: string = messag

  • TypeScript中的类型断言[as语法|<>语法]的使用

    Typescript中类型断言官方解释 要理解好类型断言,其实就深刻理解一句话:你会比TypeScript更了解某个值的详细信息 . 类型断言,断言 断言,顾名思义,我断定怎么怎么样,代入这句话里就是,我断定这个类型是什么.当然这是我们主观上的思维逻辑,程序并不认可,所以我们需要告诉程序:“相信我,我知道自己在干什么” . 这么干说,大家可能还是理解的不够透彻,我用两个函数举一个例子: /** * @param d 日期 * @param f 想要格式化的字符串 */ function date

随机推荐