栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Go语言

Go1.18 新特性:高效复制,strings, bytes 标准库新增 Clone API

Go语言 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Go1.18 新特性:高效复制,strings, bytes 标准库新增 Clone API

大家好,我是煎鱼。

Go1.18 过几周(3月份)就要发布了,先前我们已经更新了好几期新版本特性,今天给大家带来一个新的优化类的内容,是与 strings 和 bytes 标准库有关。

背景 想要更快捷复制

在日常编程中,字节 []byte 是经常需要复制的。需要写以下代码:

dup := make([]byte, len(data))
copy(dup, data)

@Ilia Choly 觉得这就太麻烦了,毕竟每次都得写一遍,又或是自己封装成如下函数:

// Clone returns a copy of b
func Clone(b []byte) []byte {
  b2 := make([]byte, len(b))
  copy(b2, b)
  return b2
}

为此想要增加一个快捷方法,不过这显然站不住脚,熟悉语法的同学会发现有现成的方式:

b2 := append([]byte(nil), b...)

一行就能实现效果,甚至更快,因为分配的切片不会被初始化为零值。

复制会共享内存

许多 Go 开发者,在写应用程序要复制切片(Slice)时,会发现复制出来的切片 s1 和原始的 s0 有内存上的关联,其本质原因在于其底层的数据结构导致,这会导致许多隐藏的问题。

示例代码如下:

import (
 "fmt"
 "reflect"
 "unsafe"
)

func main() {
 s0 := "脑子进煎鱼了"
 s1 := s0[:3]
 s0h := (*reflect.StringHeader)(unsafe.Pointer(&s0))
 s1h := (*reflect.StringHeader)(unsafe.Pointer(&s1))

 fmt.Printf("Len is equal: %tn", s0h.Len == s1h.Len)
 fmt.Printf("Data is equa: %tn", s0h.Data == s1h.Data)
}

从上述程序来看,你认为变量 s0 和 s1 相比,他们的 Len 相等吗?Data 相等吗?

输出结果如下:

Len is equal: false
Data is equa: true

咋一看,好像没问题。Len 不相等,毕竟是按索引复制的。但 Data 竟然就相等了,这为什么,是 Go 出 BUG 了吗?

这实际是与 Go 在 String 和 Slice 的底层数据结构有关的,例如 String 的运行时表现是 StringHeader。

他的底层结构如下:

type StringHeader struct {
 Data uintptr
 Len  int
}
  • Data:指向具体的底层数组。

  • Len:代表字符串切片的长度。

关键就在于 Data,本质上是一个指向底层数据的指针地址,因此在复制时,会将其也复制过去。造成不必要的复制和 “脏” 数据,引发各种奇怪的 BUG。

这个问题,正在新特性的痛点。

新特性

在 Go1.18 的新特性中,strings 和 bytes 增加了一个 Clone 方法,来解决前面提到的 2 个问题点。

源代码如下:

func Clone(s string) string {
 if len(s) == 0 {
  return ""
 }
 b := make([]byte, len(s))
 copy(b, s)
 return *(*string)(unsafe.Pointer(&b))
}
  • 通过 copy 函数对原始字符串进行复制,得到一份新的 []byte 数据。

  • 通过 *(*string)(unsafe.Pointer(&b)) 进行指针操作,实现 byte 到 string 的零内存复制转换。

至此,通过非常巧妙地方式解决了背景中的两个问题。大家也不用一直去重复写类似的代码了。

总结

一直以来,Go 中的 string 和 slice 因为底层数组指向和扩缩容机制等原因饱受争议,在末尾也给出一些公众号之前介绍过的一些 “坑”,有兴趣的读者可以看看。

本次的 1.18 新方法更新,是有一定功能作用的,在学习上也能够明确的知道 Clone 他的作用和定义,会留个心眼。

你的项目中有类似的代码吗?

往期推荐
  • Go 切片导致内存泄露,被坑两次了!

  • Go 切片这道题,吵了一个下午!

关注煎鱼,获取业内第一手消息和知识 

你好,我是煎鱼,出版过 Go 畅销书《Go 语言编程之旅》,再到获得 GOP(Go 领域最有观点专家)荣誉,点击蓝字查看我的出书之路。

日常分享高质量文章,输出 Go 面试、工作经验、架构设计,加微信拉读者交流群,和大家交流!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/945221.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号