文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

golang 中slice和string如何使用

2023-06-20 16:26

关注

这期内容当中小编将会给大家带来有关golang 中slice和string如何使用,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

slice 和 string 内部结构

slice 和 string 的内部结构可以在 $GOROOT/src/reflect/value.go 里面找到

type StringHeader struct {    Data uintptr    Len  int}type SliceHeader struct {    Data uintptr    Len  int    Cap  int}

可以看到一个 string 包含一个数据指针和一个长度,长度是不可变的

slice 包含一个数据指针、一个长度和一个容量,当容量不够时会重新申请新的内存,Data 指针将指向新的地址,原来的地址空间将被释放

从这些结构就可以看出,string 和 slice 的赋值,包括当做参数传递,和自定义的结构体一样,都仅仅是 Data 指针的浅拷贝

slice 重用

append 操作
si1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}si2 := si1si2 = append(si2, 0)Convey("重新分配内存", func() {    header1 := (*reflect.SliceHeader)(unsafe.Pointer(&si1))    header2 := (*reflect.SliceHeader)(unsafe.Pointer(&si2))    fmt.Println(header1.Data)    fmt.Println(header2.Data)    So(header1.Data, ShouldNotEqual, header2.Data)})

si1 和 si2 开始都指向同一个数组,当对 si2 执行 append 操作时,由于原来的 Cap 值不够了,需要重新申请新的空间,因此 Data 值发生了变化,在 $GOROOT/src/reflect/value.go 这个文件里面还有关于新的 cap 值的策略,在 grow 这个函数里面,当 cap 小于 1024 的时候,是成倍的增长,超过的时候,每次增长 25%,而这种内存增长不仅仅数据拷贝(从旧的地址拷贝到新的地址)需要消耗额外的性能,旧地址内存的释放对 gc 也会造成额外的负担,所以如果能够知道数据的长度的情况下,尽量使用 make([]int, len, cap) 预分配内存,不知道长度的情况下,可以考虑下面的内存重用的方法

内存重用
si1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}si2 := si1[:7]Convey("不重新分配内存", func() {    header1 := (*reflect.SliceHeader)(unsafe.Pointer(&si1))    header2 := (*reflect.SliceHeader)(unsafe.Pointer(&si2))    fmt.Println(header1.Data)    fmt.Println(header2.Data)    So(header1.Data, ShouldEqual, header2.Data)})Convey("往切片里面 append 一个值", func() {    si2 = append(si2, 10)    Convey("改变了原 slice 的值", func() {        header1 := (*reflect.SliceHeader)(unsafe.Pointer(&si1))        header2 := (*reflect.SliceHeader)(unsafe.Pointer(&si2))        fmt.Println(header1.Data)        fmt.Println(header2.Data)        So(header1.Data, ShouldEqual, header2.Data)        So(si1[7], ShouldEqual, 10)    })})

si2 是 si1 的一个切片,从第一段代码可以看到切片并不重新分配内存,si2 和 si1 的 Data 指针指向同一片地址,而第二段代码可以看出,当我们往 si2 里面 append 一个新的值的时候,我们发现仍然没有内存分配,而且这个操作使得 si1 的值也发生了改变,因为两者本就是指向同一片 Data 区域,利用这个特性,我们只需要让 si1 = si1[:0] 就可以不断地清空 si1 的内容,实现内存的复用了

PS: 你可以使用 copy(si2, si1) 实现深拷贝

string

Convey("字符串常量", func() {    str1 := "hello world"    str2 := "hello world"    Convey("地址相同", func() {        header1 := (*reflect.StringHeader)(unsafe.Pointer(&str1))        header2 := (*reflect.StringHeader)(unsafe.Pointer(&str2))        fmt.Println(header1.Data)        fmt.Println(header2.Data)        So(header1.Data, ShouldEqual, header2.Data)    })})

这个例子比较简单,字符串常量使用的是同一片地址区域

Convey("相同字符串的不同子串", func() {    str1 := "hello world"[:6]    str2 := "hello world"[:5]    Convey("地址相同", func() {        header1 := (*reflect.StringHeader)(unsafe.Pointer(&str1))        header2 := (*reflect.StringHeader)(unsafe.Pointer(&str2))        fmt.Println(header1.Data, str1)        fmt.Println(header2.Data, str2)        So(str1, ShouldNotEqual, str2)        So(header1.Data, ShouldEqual, header2.Data)    })})

相同字符串的不同子串,不会额外申请新的内存,但是要注意的是这里的相同字符串,指的是 str1.Data == str2.Data && str1.Len == str2.Len,而不是 str1 == str2,下面这个例子可以说明 str1 == str2 但是其 Data 并不相同

Convey("不同字符串的相同子串", func() {    str1 := "hello world"[:5]    str2 := "hello golang"[:5]    Convey("地址不同", func() {        header1 := (*reflect.StringHeader)(unsafe.Pointer(&str1))        header2 := (*reflect.StringHeader)(unsafe.Pointer(&str2))        fmt.Println(header1.Data, str1)        fmt.Println(header2.Data, str2)        So(str1, ShouldEqual, str2)        So(header1.Data, ShouldNotEqual, header2.Data)    })})

上述就是小编为大家分享的golang 中slice和string如何使用了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯