关于golang:Go118-新特性高效复制strings-bytes-标准库新增-Clone-API

62次阅读

共计 1934 个字符,预计需要花费 5 分钟才能阅读完成。

大家好,我是煎鱼。

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: %t\n", s0h.Len == s1h.Len)
    fmt.Printf("Data is equa: %t\n", 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)) 进行指针操作,实现 bytestring 的零内存复制转换。

至此,通过十分奇妙地形式解决了背景中的两个问题。大家也不必始终去反复写相似的代码了。

总结

始终以来,Go 中的 string 和 slice 因为底层数组指向和扩缩容机制等起因饱受争议,在开端也给出一些公众号之前介绍过的一些“坑”,有趣味的读者能够看看。

本次的 1.18 新办法更新,是有肯定性能作用的,在学习上也可能明确的晓得 Clone 他的作用和定义,会留个心眼。

你的我的项目中有相似的代码吗?

若有任何疑难欢送评论区反馈和交换,最好的关系是相互成就 ,各位的 点赞 就是煎鱼创作的最大能源,感激反对。

文章继续更新,能够微信搜【脑子进煎鱼了】浏览,本文 GitHub github.com/eddycjy/blog 已收录,学习 Go 语言能够看 Go 学习地图和路线,欢送 Star 催更。

往期举荐

  • Go 切片导致内存泄露,被坑两次了!
  • Go 切片这道题,吵了一个下午!

参考

  • bytes, strings: add Clone
  • [test: add test that we don’t optimize string([]byte(string))](https://github.com/golang/go/…)
  • proposal: provide std lib pkg Clone function to copy a string efficiently without memory sharing

正文完
 0