go强制类型转换type(a)以及范围引起的数据差异

 更新时间:2023年10月09日 14:14:26   作者:海生  
这篇文章主要为大家介绍了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位整数数据类型。

类型比特数有效数字数值范围
int6464-2^63 ( -9,223,372,036,854,775,808)2^63-1(+9,223,372,036,854,775,807 )
float32326-7-3.410(-38)~3.410(38)
float646415-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数据差异的资料请关注脚本之家其它相关文章!

相关文章

  • golang原生http包实现各种情况的get请求方式

    golang原生http包实现各种情况的get请求方式

    这篇文章主要介绍了golang原生http包实现各种情况的get请求方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • Golang使用minio替代文件系统的实战教程

    Golang使用minio替代文件系统的实战教程

    本文讨论项目开发中直接文件系统的限制或不足,接着介绍Minio对象存储的优势,同时给出Golang的实际示例代码,包括初始化客户端、读取minio对象以及设置过期策略等,需要的朋友可以参考下
    2025-01-01
  • golang实现aes-cbc-256加密解密功能

    golang实现aes-cbc-256加密解密功能

    这篇文章主要介绍了golang实现aes-cbc-256加密解密功能,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-04-04
  • golang实现读取excel数据并导入数据库

    golang实现读取excel数据并导入数据库

    Go 语言是一门适合用于编写高效且并发的 Web 应用程序的编程语言,同时也可以使用它进行数据处理和分析,本文主要介绍了如何通过go语言实现读取excel数据并导入数据库,感兴趣的小伙伴可以了解下
    2025-04-04
  • Go语言利用标准库flag编写一个命令行参数解析器

    Go语言利用标准库flag编写一个命令行参数解析器

    在日常开发中,很多工具型程序都需要通过命令行参数来传递配置,本文将通过一个小实例,演示如何使用 Go 标准库 flag 开发一个简单的命令行参数解析器
    2025-09-09
  • Go读取MySQL Date类型的避坑指南

    Go读取MySQL Date类型的避坑指南

    文章讨论了在Go中读取MySQL中的DATETIME和DATE类型数据时遇到的格式转换问题,并解释了parseTime参数的作用,并展示了在不同情况下,Go字段类型定义对读取到的时间字符串格式的影响,需要的朋友可以参考下
    2025-12-12
  • goroutine 泄漏和避免泄漏实战示例

    goroutine 泄漏和避免泄漏实战示例

    这篇文章主要为大家介绍了goroutine 泄漏和避免泄漏实战示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • Golang 使用接口实现泛型的方法示例

    Golang 使用接口实现泛型的方法示例

    这篇文章主要介绍了Golang 使用接口实现泛型的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • go语言beego框架jwt身份认证实现示例

    go语言beego框架jwt身份认证实现示例

    这篇文章主要为大家介绍了go语言beego框架jwt身份认证实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2022-04-04
  • Golang中使用Mqtt的方法示例

    Golang中使用Mqtt的方法示例

    本文介绍了Golang中使用paho.mqtt.golang库实现MQTT客户端与服务器的连接、订阅和消息收发,具有一定的参考价值,感兴趣的可以了解一下
    2025-02-02

最新评论