060-类型断言(Type Assertion)
Posted --Allen--
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了060-类型断言(Type Assertion)相关的知识,希望对你有一定的参考价值。
接口相关的知识中,最重要的不仅仅是了解接口如何实现,接口的构成(类型和值)。另一个非常非常重要的知识点就是类型断言。
正好上一篇文章所介绍的,根据接口判断 error 的类型,相当重要,这可以帮助我们根据不同的错误来制定相应的策略。
1. 类型断言
首先,类型断言,当然只能在接口上进行操作啦。普通对象你都已经知道它的类型了,还有断言的必要吗?
对于接口 x,语法形式上像 x.(T)
这样的,就称之为类型断言。x.(T)
会返回一个值。断言成功情况下,返回的值有两种可能:
- 如果 T 是普通的具体类型,
x.(T)
就会返回x
的值部分,即类型为 T 的值。 - 如果 T 仍然是接口类型,
x.(T)
会返回 T 类型的接口值
如果断言失败呢?根据你的书写形式,你可以选择让程序 panic 或者返回一个 bool 值。说这么多,不如举几个例子来实在。
var w io.Writer
w = os.Stdout
f := w.(*os.File) // 断言成功,返回 w 中的值部分。f == os.Stdout
c := w.(*bytes.Buffer) // Panic! 断言失败
如果你不希望你的程序在断言的过程上发生 panic,你可以写成下面这样:
var w io.Writer
w = os.Stdout
f, ok := w.(*os.File) // 断言成功,f == os.Stdout, ok == true
c, ok := w.(*bytes.Buffer) // 断言失败, c == nil, ok == false
什么时候用单返回值形式,什么时候用双返回值形式的断言?
当你明确要求某个接口值的类型部分是约定的类型的时候,你就使用单返回值形式。比如你和同事合作开发一个项目,你要求你同事返回的接口值的类型部分是 int,那你就直接使用单返回值的类型断言。如果你的程序 panic 了,你就可以去 diss 你的同事了 : )
2. 断言接口类型
上面的例子是断言某个接口值是某个具体类型,你也可以断言接口值可以是另一种接口类型。比如:
var w io.Writer
w = os.Stdout
rw := w.(io.ReadWriter) // 断言成功,(*os.File) 的确有 Read 和 Write 方法
_, pw := io.Pipe() // func Pipe() (*PipeReader, *PipeWriter)
w = pw
rw = pw.(io.ReadWriter) // panic, 断言失败。(*PipeWriter) 并没有实现 Read 方法
上面比较奇怪的是,我们断言 w 接口值是 io.ReadWriter 接口值,尽管 w 是 io.Writer 接口类型,但是这也没什么关系。断言一个接口是不是另一种类型,看的是这个接口内部 type 那个部分是否真的符合你断言的类型。
3. 对 nil 接口值断言
无论被断言成什么类型都会失败。
var w io.Writer
rw := w.(*os.File) // 断言失败,panic
var w io.Writer
rw, ok := w.(*os.File) // 断言失败,rw == nil, ok == false
4. 判断 error 类型
还记得上一篇文章遗留的一个问题吗?在程序的最后,有这样一段:
if e, ok := err.(syscall.Errno); ok && e == 2
fmt.Printf("Error: %v\\n", e)
现在你应该能看到这是什么意思了吧。其实非常简单,我们断言 err 接口值的类型是 syscall.Errno
,如果断言成员,那 e 就是 syscall.Errno
类型的值,同时 ok 也为 true
,最后再判断 e 的值是否为 2,如果是,就打印输出 e.
5. 总结
- 掌握类型断言
- 掌握类型言返回单值和双值的区别
以上是关于060-类型断言(Type Assertion)的主要内容,如果未能解决你的问题,请参考以下文章