在Go语言中类型断言的语法格式如下:
value, ok := x.(T)
类型断言失败,不会发生panic。根据ok判断是否成功
或者
value:= x.(T)
类型断言失败,会发生panic
其中,x 表示一个接口的类型,T 表示一个具体的类型(也可为接口类型)。
该断言表达式会返回 x 的值(也就是 value)和一个布尔值(也就是 ok),可根据该布尔值判断 x 是否为 T 类型:
- 如果断言的类型T是一个具体类型,类型断言检查x的动态类型是否和T相同。如果这个检查成功了,类型断言的结果是x的动态值,它的类型是T。
- 如果断言的类型T是一个接口类型,类型断言检查是否x的动态类型满足T。如果这个检查成功了,动态值没有获取到;这个结果仍然是一个有相同动态类型和值部分的接口值,但是结果为类型T。换句话说,对一个接口类型的类型断言改变了类型的表述方式,改变了可以获取的方法集合(通常更大),但是它保留了接口值内部的动态类型和值的部分。
- 无论 T 是什么类型,如果 x 是 nil 接口值,类型断言都会失败。
举例
package main
import (
"fmt"
)
type i1 interface {
hello()
}
type i2 interface {
hello()
hello2()
}
type i1St struct {
}
type i2St struct {
}
func (s i1St) hello() {
}
func (s i2St) hello() {
}
func (s i2St) hello2() {
}
func main() {
var myI1 i1
var myI2 i2
var myI1St i1St
var myI2St i2St
myI1 = myI1St
myI2 = myI2St
a, aOk := myI1.(i1)
fmt.Printf("a, aOk := myI1.(i1) is return %v,%t,type is %T\n", a, aOk, a)
b, bOk := myI1.(i2)
fmt.Printf("b, bOk := myI1.(i2) is return %v,%t,type is %T\n", b, bOk, a)
c, cOk := myI2.(i1)
fmt.Printf("c, cOk := myI2.(i1) is return %v,%t,type is %T\n", c, cOk, a)
d, dOk := myI2.(i1)
fmt.Printf("d, dOk := myI2.(i1) is return %v,%t,type is %T\n", d, dOk, a)
}
结果如下:
a, aOk := myI1.(i1) is return {},true,type is main.i1St
b, bOk := myI1.(i2) is return <nil>,false,type is main.i1St
c, cOk := myI2.(i1) is return {},true,type is main.i1St
d, dOk := myI2.(i1) is return {},true,type is main.i1St
如果相反地断言的类型T是一个接口类型,然后类型断言检查是否x的动态类型满足T。例子
var w io.Writer
w = os.Stdout
rw := w.(io.ReadWriter) // success: *os.File has both Read and Write
w = new(ByteCounter)
rw = w.(io.ReadWriter) // panic: *ByteCounter has no Read method
w和rw都持有os.Stdout,因此它们都有一个动态类型*os.File,但是变量w是一个io.Writer类型,只对外公开了文件的Write方法,而rw变量还公开了它的Read方法。
判断接口是否为nil
var i interface{}
res, ok := i.(interface{})
fmt.Printf("%v - %t,type is %T\n", res, ok, res)
结果如下:
<nil> - false,type is <nil>
如果需要区分多种类型,可以使用 type switch 断言,这个将会比一个一个进行类型断言更简单、直接、高效。
package main
import (
"fmt"
)
func main() {
var a int
a = 10
switchType(a)
var i interface{}
switchType(i)
switchType(10.5)
}
func switchType(a interface{}) {
switch a.(type) {
case int:
fmt.Println("the type is int")
case string:
fmt.Println("the type is string")
case float64:
fmt.Println("the type is float")
case nil:
fmt.Println("the type is nil")
default:
fmt.Println("unknown type")
}
}
结果如下:
the type is int
the type is nil
the type is float