Golang: 注意空接口运行时类型 (0)

使用空接口的时候一定注意其运行时类型,Golang没有自动转换。

专栏的介绍可以参考 《GotchaGolang专栏》,代码可以看《宝库-Gotcha》

记录碰到的关于 interface 运行时类型的问题。

案例

话不多说,直接上代码: (两份代码相比较,应该能看出问题吧)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import (
"fmt"
"reflect"
)

func main() {
s := []interface{}{true, 1, "yes"}
e := s[0]
fmt.Println(e, reflect.TypeOf(e)) // true bool

//but when used this way:
if e {
fmt.Println("This value is true")
} //complains : non-bool e (type interface {}) used as if condition
}

编译时直接报错了,意思是说,e 的类型是 interface{} 但是却用于 if 条件语句。
反射得到的结果是 e 的运行时类型,怎么跳过编译器编译检查呢?(编译检查的是原始类型不是运行时类型)

方式一: (type assertion)

1
2
3
4
//way one: type assertion
if e.(bool) {
fmt.Println("This value is true")
} //complains : non-bool e (type interface {}) used as if condition

需要担心的是,类型断言如果失败,直接 panic

方式二: (using == to get the runtime type)

1
2
3
4
//way two: using == to get the runtime type
if e == true {
fmt.Println("This value is true too");
}

编译器之所以报错是因为编译器不对 interface{} 接口实现的类型做任何 automatic change/convert。
但是 e == true 相当于让一个 interface{} 和 bool 类型进行比较,这就要检查运行时类型了,所以编译器不多说话。

官方文档: 如果一个 non-interface X 和 interface T 比较。如果 X 实现了 T 接口,则可以进行比较,因为他们 dynamic type is identical/equals. (运行时类型兼容或者相同既可以比较, 所以利用 == 来检查运行时类型接口)

完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
"fmt"
"reflect"
)

func main() {
s := []interface{}{true, 1, "yes"}
e := s[0]
fmt.Println(e, reflect.TypeOf(e)) // true bool

//but when used this way:
/* if e {
fmt.Println("This value is true")
} //complains : non-bool e (type interface {}) used as if condition */

//way one: type assertion
if e.(bool) {
fmt.Println("This value is true")
} //complains : non-bool e (type interface {}) used as if condition

//way two: using == to get the runtime type
if e == true {
fmt.Println("This value is true too");
}
}

总结

interface{} 本身不携带任何类型信息(编译时), 并且编译时不会去检查运行时实际类型。
所以当你要使用其运行时类型信息,那么 access to it,就像上面的 == 比较的时候,就会取其运行时类型。

教训是:偷懒的写法,你确定不会出问题?但凡有一丝疑虑,就要仔细推敲一下。


Merlin 2018.3 Golang 坑

文章目录
  1. 1. 案例
  2. 2. 总结
|