go强制类型转换type(a)以及范围引起的数据差异
作者:海生
一、介绍
golang中的类型转换分强制类型转换和类型断言普通变量类型int,float,string 都可以使用type(a)这种形式来进行强制类型转换
二、数字的类型转换int和float
1、整数类型 int
func TestInt(t *testing.T) { var i int = -1 var i8 int8 = int8(i) var i16 int16 = int16(i) var i32 int32 = int32(i) var i64 int64 = int64(i) t.Log(i, i8, i16, i32, i64) //-1 -1 -1 -1 -1 var n int = 1111111 var n8 int8 = int8(n) var n16 int16 = int16(n) var n32 int32 = int32(n) var n64 int64 = int64(n) t.Log(n, n8, n16, n32, n64) //1111111 71 -3001 1111111 1111111 }
我们发现当 在转换n的过程中,转成int8和int16的时候,出现了错误,为什么会这样?
在于int类型在mac上是默认的64个bit,
int8 表示 -128 到 127 之间的整数值 (8个bit)
int16 表示 -32768 和 32767 之间的整数值 (16个bit)
他们之间能够存储的范围是不相同的,如果超过了某个类型的范围就会出错。
2、正整数类型 uint
func TestUint(t *testing.T) { var i uint = 1 var i8 uint8 = uint8(i) var i16 uint16 = uint16(i) var i32 uint32 = uint32(i) var i64 uint64 = uint64(i) t.Log(i, i8, i16, i32, i64) //1 1 1 1 1 var u uint = 1111111 var u8 uint8 = uint8(u) var u16 uint16 = uint16(u) var u32 uint32 = uint32(u) var u64 uint64 = uint64(u) t.Log(u, u8, u16, u32, u64) //1111111 71 62535 1111111 1111111 }
在类型范围内的数据转换正确,范围外的转换错误。
3、int和uint之间的强制转换
func TestInt2(t *testing.T) { var i int = -1 var i8 uint8 = uint8(i) var i16 uint16 = uint16(i) var i32 uint32 = uint32(i) var i64 uint64 = uint64(i) t.Log(i, i8, i16, i32, i64) //-1 255 65535 4294967295 18446744073709551615 var n int = 1 var n8 uint8 = uint8(n) var n16 uint16 = uint16(n) var n32 uint32 = uint32(n) var n64 uint64 = uint64(n) t.Log(n, n8, n16, n32, n64) //1 1 1 1 1 var u int = 1111111 var u8 uint8 = uint8(u) var u16 uint16 = uint16(u) var u32 uint32 = uint32(u) var u64 uint64 = uint64(u) t.Log(u, u8, u16, u32, u64) //1111111 71 62535 1111111 1111111 }
我们发现当每种类型范围不一样的话,转换不留神还是会有很大的错误。
4、float32和float64的强制转换
func TestFloat(t *testing.T) { var f32 float32 = 333.333 var f64 float64 = float64(f32) t.Log(f32, f64) //333.333 333.3330078125 //都在各自的范围内 var fl64 float64 = 333.333 var fl32 float32 = float32(fl64) t.Log(fl64, fl32) //333.333 333.333 //大类型的范围 超过小的类型范围 var flo64 float64 = 33333333333333333.333 var flo32 float32 = float32(flo64) t.Log(flo64, flo32) //333.333 333.333 }
首先我们判断float32和float64有什么不同,因为使用内存大小不一样,导致精度以及范围的不同。
- float32和float64互相转化,因为精度不一样,导致数据差异
- float32和float64互相转化,因为范围不一样,导致数据差异
5、float和int互相转换
func TestFloatInt(t *testing.T) { var i int = 333 var f32 float32 = float32(i) var f64 float64 = float64(i) t.Log(i, f32, f64) //333 333 333 var f float32 = 333.3 var n int = int(f) var n8 int8 = int8(f) var n16 int16 = int16(f) var n32 int32 = int32(f) var n64 int64 = int64(f) t.Log(f, n, n8, n16, n32, n64) //333.3 333 77 333 333 333 }
因为是mac系统,我这里int是有符号64位整数数据类型。
类型 | 比特数 | 有效数字 | 数值范围 |
---|---|---|---|
int64 | 64 | -2^63 ( -9,223,372,036,854,775,808) | 2^63-1(+9,223,372,036,854,775,807 ) |
float32 | 32 | 6-7 | -3.410(-38)~3.410(38) |
float64 | 64 | 15-16 | -1.710(-308)~1.710(308) |
基本上当int转成float类型只要在范围内的就没有啥问题
而float转成int的时候,需要考虑,小数点后面的会自动的舍去,以及范围问题。
三、指针unsafe.Pointer任意类型与具体指针类型的转换
注意,指针unsafe.Pointer任意类型,只能转成 具体类型的指针类型
如转成int类型的指针类型 *int
强制准换的语法为 type(a),那么就是这里(*int)(a),而不是int(a)!
1、指针unsafe.Pointer转成int指针类型
func TestIntPointer(t *testing.T) { //范围内可以正确转化的情况 var i int = 100 pi := unsafe.Pointer(&i) //转成int相关类型 var n *int = (*int)(pi) var n8 *int8 = (*int8)(pi) var n16 *int16 = (*int16)(pi) var n32 *int32 = (*int32)(pi) var n64 *int64 = (*int64)(pi) t.Log(*n, *n8, *n16, *n32, *n64)//100 100 100 100 100 //-------------------------- //范围超出的情况 var i2 int = 10000 pi2 := unsafe.Pointer(&i2) //转成int相关类型 var nn *int = (*int)(pi2) var nn8 *int8 = (*int8)(pi2) var nn16 *int16 = (*int16)(pi2) var nn32 *int32 = (*int32)(pi2) var nn64 *int64 = (*int64)(pi2) t.Log(*nn, *nn8, *nn16, *nn32, *nn64)//10000 16 10000 10000 10000 }
这里虽然是指针了,但还是需要注意具体类型的范围。
不然超出类型的最大或者最小值,仍然是错误的。
2、指针unsafe.Pointer转成struct指针类型
还是type(a)的方式,这里的a变量为 unsafe.Pointer(&a)
type为 (*Struct)
完整的表达式为 (*Struct)(unsafe.Pointer(&a))
func TestStruct(t *testing.T) { //有一个struct结构体S,里面width和height两个int类型 type S struct { wight int height int } s := S{ wight: 5, height: 6, } p := unsafe.Pointer(&s) //{5 6} t.Log(s) //测试转成为T,T里面有w和h两个int类型 type T struct { w int h int } st := (*T)(p) t.Log(*st) //{5 6} }
发现虽然S和T两个结构体不一样,但却转成了正确的值,为什么?
因为指针关注的内存控股,不管是S里的wight或者T里面的w,其实都是int类型,占用了相同的内存
所以能够正确的解析出来
如果此时我们把 T的类型改一下成int8试试,就会发现错误
func TestStruct(t *testing.T) { //有一个struct结构体S,里面width和height两个int类型 type S struct { wight int height int } s := S{ wight: 5, height: 6, } p := unsafe.Pointer(&s) //{5 6} t.Log(s) //测试转成为T,T里面有w和h两个int8类型 type T struct { w int8 h int8 } st := (*T)(p) t.Log(*st) //{5 0} }
第一个获取的5值,是因为在指针的0偏移量所以能够获取到,也正好在范围内,如果S.wight=10000
那么第一个也会错误,如下
func TestStruct(t *testing.T) { //有一个struct结构体S,里面width和height两个int类型 type S struct { wight int height int } s := S{ wight: 10000, height: 6, } p := unsafe.Pointer(&s) //{10000 6} t.Log(s) //测试转成为T,T里面有w和h两个int8类型 type T struct { w int8 h int8 } st := (*T)(p) t.Log(*st) //{16 39} }
所以我们可以得出如果是指针类型的话,只要里面的指针是一样的,才能强制转换成正确的值。
以上就是go强制类型转换type(a)以及范围引起的数据差异的详细内容,更多关于go强制类型转换type数据差异的资料请关注脚本之家其它相关文章!