一个新细节,Go 1.17 将允许切片转换为数组指针!

大家好,我是煎鱼。

今天是周末的,虽然只有一天。给大家分享一个 Go1.17 的快讯。一天增长一个吸鱼技巧!

在 Go 语言中,一个切片(slice)包含了对其支持数组的引用,无论这个数组是作为一个独立的变量存在于某个地方,还是仅仅是一个为支持分片而分配的匿名数组。

其切片基本结构都如下:

// runtime/slice.go
type slice struct {
 array unsafe.Pointer // 指向底层数组的指针
 len   int // 长度 
 cap   int // 容量
}

目前切片这种支持数组的方式可能会导致切片出现有趣的内存泄漏[1]或对你的切片产生令人惊讶的变化[2]

另外很重要的一点,在 Go 1.16 及以前,不存在将从切片类型转换为数组类型的安全方法,比较无奈。

我们只能通过调用标准库 reflect 或 unsafe,通过编写不安全的代码来做到这一点:

(*[10]byte)(unsafe.Pointer(&b[0]))

显然这是不优雅的,官方自己都不推荐使用 unsafe,一旦处理出错了,可能还会导致致命错误,比较不可控。

其实早在2009 年,在 Go 发布后不久(远在 Go 1.0 发布之前),就有人提出相关疑惑,希望解决这个问题:

终于,在即将到来的 Go 1.17 中,这将成为可能,因为从 commit-id #1c268431f4 开始的一系列变化,更新了规范:

新的规范中对此的描述很直接:

Converting a slice to an array pointer yields a pointer to the underlying array of the slice. If the length of the slice is less than the length of the array, a run-time panic occurs.

  • 如果切片的长度比数组的长度长是无害,能够正常运行。

  • 如果比数组长的切片,意味着你的数组将不能访问原始切片的所有支持数组。

另外规范中提供了一些新的例子,在 Go1.17 中我们可以这么用:

s := make([]byte, 2, 4)
s0 := (*[0]byte)(s)      // s0 != nil
s2 := (*[2]byte)(s)      // &s2[0] == &s[0]
s4 := (*[4]byte)(s)      // panics: len([4]byte) > len(s)

var t []string
t0 := (*[0]string)(t)    // t0 == nil
t1 := (*[1]string)(t)    // panics: len([1]string) > len(s)
  • 变量 s2 的转换:其将切片底层的数组转换了出来,这种转换不会(也不能)分配一个新的数组,从而保证了它的效率。

  • 变量 s0 和 t0 的转换:其将一个非空的片断转换为一个 0 长度的数组。虽然长度为 0 的数组,你不能用它做任何事情,但依然必须给一个有效的指针,也就是 nil。

需要注意,现在还没有办法像类型断言那样,检查他是否会因为越界等原因出现 panic 事件。如果你认为你可能有一个太短的片断,可能会导致 panic 事件,那么你需要使用 if 来进行预判断。

同时标准库 reflect 也会进行更新,以便于支持从切片到数组指针的转换[3],如果你正在用 reflect 做相关转换工作,建议阅读该提交中的注意事项。

你对 Go 语言在类型转换上有没有其它的一些想法和诉求,或者有没有踩过什么坑?

欢迎大家在评论区留言交流。

参考资料

[1]

有趣的内存泄漏: https://utcc.utoronto.ca/~cks/space/blog/programming/GoSlicesMemoryLeak

[2]

切片产生令人惊讶的变化: https://utcc.utoronto.ca/~cks/space/blog/programming/GoSliceMutability

[3]

commit-id #760d3b2a16: https://github.com/golang/go/commit/760d3b2a16544aab553ca7ec6e6ed3bf4dc9aa3f

关注煎鱼,吸取他的知识 ????

你好,我是煎鱼。高一折腾过前端,参加过国赛拿了奖,大学搞过 PHP。现在整 Go,在公司负责微服务架构等相关工作推进和研发。

从大学开始靠自己赚生活费和学费,到出版 Go 畅销书《Go 语言编程之旅》,再到获得 GOP(Go 领域最有观点专家)荣誉,点击蓝字查看我的出书之路

日常分享高质量文章,输出 Go 面试、工作经验、架构设计,公众号内回复【加群】拉你进读者交流群。记得点赞!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值