go存在4种类型转换分别为:断言、强制、显式、隐式。golang
一般说的类型转换是指断言,强制在平常不会使用到、显示是基本的类型转换、隐式使用到可是不会注意到。断言、强制、显式三类在go语法描述中均有说明,隐式是在平常使用过程当中总结出来。c#
断言经过判断变量是否能够转换成某一个类型函数
一个简单的断言表达式:测试
var s = x.(T)
ui
若是x不是nil,且x能够转换成T类型,就会断言成功,返回T类型的变量s。若是T不是接口类型,则要求x的类型就是T,若是T是一个接口,要求x实现了T接口。google
若是断言类型成立,则表达式返回值就是T类型的x,若是断言失败就会触发panic。指针
上述表所示再断言失败就会panic,go提供了另一种带返回是否成立的断言语法:code
s, ok := x.(T)
接口
该方法和第一种差很少同样,可是ok会返回是否断言成功不会出现panic,ok就表示是不是成功了。
go语法种还提供了另一种类型switch的断言方法。
x断言成了type类型,type类型具体值就是switch case的值,若是x成功断言成了某个case类型,就能够执行那个case,此时i := x.(type)
返回的i就是那个类型的变量了,能够直接看成case类型使用。
switch i := x.(type) { case nil: printString("x is nil") // type of i is type of x (interface{}) case int: printInt(i) // type of i is int case float64: printFloat64(i) // type of i is float64 case func(int) float64: printFunction(i) // type of i is func(int) float64 case bool, string: printString("type is bool or string") // type of i is type of x (interface{}) default: printString("don't know the type") // type of i is type of x (interface{}) }
强制类型转换经过修改变量类型
该方法不常见,主要用于unsafe包和接口类型检测,须要懂得go变量的知识。
本文档仅大概说明一下,具体研究请求查找相关资料。unsafe语法文档 镜像地址
var f float64 bits = *(*uint64)(unsafe.Pointer(&f)) type ptr unsafe.Pointer bits = *(*uint64)(ptr(&f)) var p ptr = nil
float64就强制转换成uint64类型,float的地址就是一个值可是类型是float64,而后建立了一个uint64类型变量,地址值也是float64的地址值,两个变量值相同类型不一样,强制转换了类型。
unsafe强制转换是指针的底层操做了,用c的朋友就很熟悉这样的指针类型转换,利用内存对齐才能保证转换可靠,例如int和uint存在符号位差异,利用unsafe转换后值可能不一样,可是在内存存储二进制如出一辙。
例以下列代码:
var _ Context = (*ContextBase)(nil)
nil的类型是nil地址值为0,利用强制类型转换成了*ContextBase,返回的变量就是类型为*ContextBase地址值为0,而后Context=xx
赋值若是xx实现了Context接口就没事,若是没有实如今编译时期就会报错,实现编译期间检测接口是否实现。
一个显式转换的表达式T(x) ,其中T是一种类型而且x是可转换为类型的表达式T,例如:uint(666)
。
在如下任何一种状况下,变量x均可以转换成T类型:
例以下列代码利用了规则进行转换,规则实现能够参考reflect.Value.Convert方法逻辑:
int64(222) []byte("ssss") type A int A(2)
隐式类型转换平常使用并不会感受到,可是运行中确实出现了类型转换,如下列出了两种。
type Reader interface { Read(p []byte) (n int, err error) } type ReadCloser interface { Reader Close() error } var rc ReaderClose r := rc
ReaderClose接口组合了Reader接口,可是r=rc的赋值时仍是类型转换了,go使用系统内置的函数执行了类型转换。之前遇到过相似接口组合类型的变量赋值,而后使用pprof和bench测试发现了这一细节,在接口类型转移时浪费了一些性能。
type Handler func() func NewHandler() Handler { return func() {} }
虽然type定义了Handler类型,可是Handler和func()是两种实际类型,类型不会相等,使用反射和断言均会出现两种类型不一样。
二者类型不一样验证代码:
package main import ( "fmt" "reflect" ) type Handler func() func a() Handler { return func() {} } func main() { var i interface{} = main _, ok := i.(func()) fmt.Println(ok) _, ok = i.(Handler) fmt.Println(ok) fmt.Println(reflect.TypeOf(main) == reflect.TypeOf((*Handler)(nil)).Elem()) } // true // false // false