7.3. 类型断言总结
7.1节介绍了如何从类型为 interface{}
的接口值中通过类型断言获取它所包含的具体值,该用法对于非空接口值依然成立,例如:
// 版权 @2023 凹语言 作者。保留所有权利。
type Printer interface {
Print()
}
type T1 struct {
i: i32
}
func T1.Print { println("This is T1, this.i:", this.i) }
type T2 struct {
s: string
}
func T2.Print { println("This is T2, this.s:", this.s) }
func doConcrete(p: Printer) {
switch v := p.(type) {
case *T1:
v.Print() // 方法直接调用,而非接口调用
case *T2:
v.Print()
}
}
func main {
v1 := T1{i: 42}
doConcrete(&v1) // This is T1, this.i: 42
v2 := T2{s: "hello"}
doConcrete(&v2) // This is T2, this.s: hello
}
注意函数 doConcrete
中 v.Print()
是直接调用,而非接口调用,因为在 case *T1
分支中,v
的类型是 *T1
。另外,非空接口值也可以通过 v, ok = iface.(Type)
形式进行具体类型断言,这与7.1节中空接口值的对应用法一致。
实际上类型断言的用法还不仅于此,在某些情况下,一个具体类型 *T
可能同时满足多个接口 I1
、I2
,那么当一个 I1
的接口值中包含的具体值类型为 *T
时,可以在该接口值上通过类型断言,直接获取一个类型为 I2
的接口值,例如:
// 版权 @2023 凹语言 作者。保留所有权利。
type I1 interface {
f1()
}
type I2 interface {
f2()
}
type T struct {
i: i32
}
func T.f1 { println("T.f1(), T.i:", this.i) }
func T.f2 { println("T.f2(), T.i:", this.i) }
func main {
v1 := T{i: 42}
i1: I1 = &v1
i1.f1() // T.f1(), T.i: 42
i2, ok := i1.(I2) // 断言为另一个接口
if ok {
i2.f2() // T.f2(), T.i: 42
}
}
这种用法一般常见于从 interface{}
接口值中获取非空接口。
除了形如 v, ok = iface.(Type)
的类型断言外,还有另一种模式的类型断言:
v = iface.(Type)
该模式取消了操作成功标志的返回值 ok
,只返回被断言类型的值。如果类型断言失败,则会触发运行时异常,建议仅在完全确认断言不会失败的情况下才使用该模式。