Files
the-way-to-go_ZH_CN/eBook/11.3.md
2015-11-02 17:17:45 +08:00

96 lines
3.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 11.3 类型断言:如何检测和转换接口变量的类型
一个接口类型的变量 `varI` 中可以包含任何类型的值,必须有一种方式来检测它的 **动态** 类型,即运行时在变量中存储的值的实际类型。在执行过程中动态类型可能会有所不同,但是它总是可以分配给接口变量本身的类型。通常我们可以使用 **类型断言** 来测试在某个时刻 `varI` 是否包含类型 `T` 的值:
```go
v := varI.(T) // unchecked type assertion
```
**varI 必须是一个接口变量**,否则编译器会报错:`invalid type assertion: varI.(T) (non-interface type (type of varI) on left)`
类型断言可能是无效的,虽然编译器会尽力检查转换是否有效,但是它不可能预见所有的可能性。如果转换在程序运行时失败会导致错误发生。更安全的方式是使用以下形式来进行类型断言:
```go
if v, ok := varI.(T); ok { // checked type assertion
Process(v)
return
}
// varI is not of type T
```
如果转换合法,`v``varI` 转换到类型 `T` 的值,`ok` 会是 `true`;否则 `v` 是类型 `T` 的零值,`ok``false`,也没有运行时错误发生。
**应该总是使用上面的方式来进行类型断言**
多数情况下,我们可能只是想在 `if` 中测试一下 `ok` 的值,此时使用以下的方法会是最方便的:
```go
if _, ok := varI.(T); ok {
// ...
}
```
示例 11.4 [type_interfaces.go](examples/chapter_11/type_interfaces.go)
```go
package main
import (
"fmt"
"math"
)
type Square struct {
side float32
}
type Circle struct {
radius float32
}
type Shaper interface {
Area() float32
}
func main() {
var areaIntf Shaper
sq1 := new(Square)
sq1.side = 5
areaIntf = sq1
// Is Square the type of areaIntf?
if t, ok := areaIntf.(*Square); ok {
fmt.Printf("The type of areaIntf is: %T\n", t)
}
if u, ok := areaIntf.(*Circle); ok {
fmt.Printf("The type of areaIntf is: %T\n", u)
} else {
fmt.Println("areaIntf does not contain a variable of type Circle")
}
}
func (sq *Square) Area() float32 {
return sq.side * sq.side
}
func (ci *Circle) Area() float32 {
return ci.radius * ci.radius * math.Pi
}
```
输出:
The type of areaIntf is: *main.Square
areaIntf does not contain a variable of type Circle
程序行中定义了一个新类型 `Circle`,它也实现了 `Shaper` 接口。 `t, ok := areaIntf.(*Square); ok ` 测试 `areaIntf` 里是否一个包含 'Square' 类型的变量,结果是确定的;然后我们测试它是否包含一个 'Circle' 类型的变量,结果是否定的。
**备注**
如果忽略 `areaIntf.(*Square)` 中的 `*` 号,会导致编译错误:`impossible type assertion: Square does not implement Shaper (Area method has pointer receiver)`
## 链接
- [目录](directory.md)
- 上一节:[接口嵌套接口](11.2.md)
- 下一节:[类型判断type-switch](11.4.md)