概述
由于Go语言不允许隐式类型转换,不同的类型之间的转换必须做显示的类型转换。而类型转换和类型断言的本质,就是把一个类型转换到另一个类型。
不过Go语言必须做显示的类型转换的要求也有例外的情况:
- 当普通 T 类型变量向
I
接口类型转换时,是隐式转换的(编译时转换);(T->I) - 当
IX
接口变量向
I
接口类型转,是隐式转换的(编译完成时转换的);(I->I)
类型之间转换的例子
下面是Go语言规范给出的部分例子:
*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
类型的语法是T(x)
.
如果对于某些地方的优先级拿不准可以自己加()
约束.
最后一个转换就是一个容易混淆的语句, 因此需要用括号(func() int)(x)
提高优先级.
还有一个容易混淆的地方是 只读和只写的通道类型 <-chan int
/chan<- int
.
变量类型转换方式
Go语言的转换分两种:类型转换 和 类型断言
1. 类型转换
go里面的类型转换写法:
T(x)
(1)、语法:<结果类型> := <目标类型> ( <表达式> )
(2)、类型转换是用来在不同但相互兼容的类型之间的相互转换的方式,所以,当类型不兼容的时候,是无法转换的。如下:
var var1 int = 7 fmt.Printf("%T->%v\n", var1, var1) //int->7 var2 := float32(var1) fmt.Printf("%T->%v\n", var2, var2) //float32->7
值得注意的是,如果某些类型可能引起误会,应该用括号括起来转换,如下:
//创建一个int变量,并获得它的指针 var1 := new(int32) fmt.Printf("%T->%v\n", var1, var1) var2 := *int32(var1) fmt.Printf("%T->%v\n", var2, var2)
*int32(var1)相当于*(int32(var1)),一个指针,当然不能直接转换成一个int32类型,所以该表达式直接编译错误。将该表达式改为 (*int32)(var1)就可以正常输出了。
2. 类型断言(Type Assertion)
类型断言用于提取接口的基础值
go里面的类型断言写法:
x.(T)
其中x为interface{}类型,T是要断言的类型。
(1)语法:
<目标类型的值>,<布尔参数> := <表达式>.( 目标类型 ) // 安全类型断言
<目标类型的值> := <表达式>.( 目标类型 ) //非安全类型断言
(2)类型断言的本质,跟类型转换类似,都是类型之间进行转换,不同之处在于,类型断言实在接口之间进行,相当于Java中,对于一个对象,把一种接口的引用转换成另一种。
x.(T) 检查x的动态类型是否是T,其中x必须是接口值。
我们先来看一个最简单的错误的类型断言:
func test() { var i interface{} = "kk" j := i.(int) fmt.Printf("%T->%d\n", j, j) }
var i interface{} = "KK" 某种程度上相当于java中的,Object i = "KK";
现在把这个 i 转换成 int 类型,系统内部检测到这种不匹配,就会调用内置的panic()函数,抛出一个异常。
改一下,把 i 的定义改为:var i interface{} = 99,就没问题了。输出为:
int->99
以上是不安全的类型断言。我们来看一下安全的类型断言:
func test() { var i interface{} = "TT" j, b := i.(int) if b { fmt.Printf("%T->%d\n", j, j) } else { fmt.Println("类型不匹配") } }
输出“类型不匹配”。
在理解有关接口的相关转换前,我们先要理解Go语言中的接口类型:interface{}
定义格式:
type IA interface {} //声明了一个接口(没有函数集合时,是空接口类型)
申明一个空接口类型时,我们在定义“空接口类型”的变量时,可以赋值任意类型的值,如
package main import ( "fmt" ) type IA interface {} //空接口类型 func main() { var a IA = 1 //int var b IA = 1.1 //float var c IA = false //bool fmt.Println(a,b,c) }
接口类型(interface{})作为函数形式参数时,则该函数可以接受任意类型的变量,但对于函数内部,该变量仍然为interface{}类型(空接口类型)
package main import ( "fmt" ) func test(a interface{}) { fmt.Printf("%T->%v\n", a, a) } func main() { test(1) test(1.1) test(true) }
输出结果:
int->1 float64->1.1 bool->true
什么叫在在 函数内部,该变量任然为interface{}类型,如:
package main import "fmt" //用于输出数组元素 func echoArray(a interface{}){