leisore 10 лет назад
Родитель
Сommit
e112dd2ebc
2 измененных файлов с 97 добавлено и 0 удалено
  1. 96 0
      eBook/11.3.md
  2. 1 0
      eBook/directory.md

+ 96 - 0
eBook/11.3.md

@@ -0,0 +1,96 @@
+# 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 {
+    // ...
+}
+```
+
+TODO ??:In this form shadowing the variable varI by giving varI and v the same name is sometimes done.
+
+示例 11.4 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 接口嵌套接口](11.2.md)
+- 下一节:[11.4 类型switch](11.4.md)

+ 1 - 0
eBook/directory.md

@@ -96,6 +96,7 @@
 - 第11章:[接口(interface)与反射(reflection)](11.0.md)
     - 11.1 [接口是什么](11.1.md)
     - 11.2 [接口嵌套接口](11.2.md)
+    - 11.3 [11.3 如何检测和转换接口变量的类型:类型断言](11.3.md)
 
 ## 第三部分:Go 高级编程