类型转换和类型断言

Go语言的类型转换和类型断言:

  1. 类型转换在编译期完成,包括强制转换和隐式转换
  2. 类型断言在运行时确定,包括安全类型断言和非安全类型断言

Go语言要求不同类型之间必须做显式的类型转换。但似乎涉及到接口类型时,就会有所不同。

T(x),类型转换是将一个值x转换成特定类型T.

1
2
3
4
5
6
7
8
*Point(p)        // same as *(Point(p))
(*Point)(p)      // p is converted to *Point
<-chan int(c)    // same as <-(chan int(c))
(<-chan int)(c)  // c is converted to <-chan int
func()(x)        // function signature func() x
(func())(x)      // x is converted to func()
(func() int)(x)  // x is converted to func() int
func() int(x)    // x is converted to func() int (unambiguous)

x.(T),类型断言是将接口类型的值x,转换成类型T。

格式为:

1
2
3
x.(T)
v := x.(T)
v, ok := x.(T)

类型断言的必要条件是x是接口类型,非接口类型的x不能做类型断言:

1
2
var i int = 10
v := i.(int) //错误

T可以是非接口类型,如果想断言合法,则T应该实现x的接口。

T也可以是接口,则x的动态类型也应该实现接口T。

1
2
3
4
5
6
var x interface{} = 7  // x 的动态类型为int, 值为 7
i := x.(int)           // i 的类型为 int, 值为 7
type I interface { m() }
var y I
s := y.(string)        // 非法: string 没有实现接口 I (missing method m)
r := y.(io.Reader)     // y如果实现了接口io.Reader和I的情况下,  r的类型则为io.Reader

类型断言如果非法,运行时时候就会出现 impossible type assertion panic,为了避免这种情况,可以使用下面的语法:

1
2
3
v, ok = x.(T)
v, ok := x.(T)
var v, ok = x.(T)

ok代表类型断言是否合法,如果非法ok =false,v为T的零值,这样就不会出现运行时panic了。

接口之间转换

接口之间在编译期间可以确定的情况下可以使用隐式类型转换,当然也可以用强制类型转换(不常用),所有情况下都可以使用类型断言。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
type A interface {}
type B interface {Foo()}
// 编译时无法确定能不能转换,因此用断言
var a A
var b = a.(B)
// 编译时,可以确定
var c B
var d = A(c)
// or var d = c
// or d = c.(A)

接口和类型之间的转换

普通类型向接口转换,可以使用隐式类型转换

1
2
3
4
type A interface {}
var s = "abc"
var a A
a = s

接口向普通类型转换,只能使用类型断言,因为编译器无法确定

1
2
3
4
type A interface {}
var s string
var a A
s = a.(string)

type switch

switch是一个条件语句,它可以判断某个值是否匹配某个case clause。但是对于type switch,它检查的是值x的类型T是否匹配某个类型。

格式如下,类型类型断言,但是括号内的不是某个具体的类型,而是单词type:

1
2
3
switch x.(type) {
// cases
}

type switch语句中可以有一个简写的变量声明,这种情况下,等价于这个变量声明在每个case clause隐式代码块的开始位置。如果case clause只列出了一个类型,则变量的类型就是这个类型,否则就是原始值的类型。

假设下面的例子中x的类型为x interface{}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
switch i := x.(type) {
case nil:
  printString("x is nil") // i的类型是 x的类型 (interface{})
case int:
  printInt(i) // i的类型 int
case float64:
  printFloat64(i) // i的类型是 float64
case func(int) float64:
  printFunction(i) // i的类型是 func(int) float64
case bool, string:
  printString("type is bool or string") // i的类型是 x (interface{})
default:
  printString("don't know the type") // i的类型是 x的类型 (interface{})
}

type switch 不支持 fallthrought

也许你已经看到上面的例子中有一个case clause中的类型是nil,它用来匹配x为nil的interface{}的情况。