【golang】切片

基本概念

切片看上去是一个可变长度的数组,实际上底层是一个结构体。结构体包含三个基本元素:1,指针(*[]type),指向一个连续的内存空间,也就是一个数组; 2,元素个数(len),可以访问的元素的个数;3,指针指向的数组的空间的长度(cap)

其中,len个元素会被初始化为默认零值,未初始化的元素不可访问。切片结构体详解如下图:

 

代码

func TestSliceInit(t *testing.T) {
    // var s0 []int //如果声明时不赋值,此时切片中元素个数和指针指向的空间长度固定均为0,其实此时切片s并不存在
    s1 := []int{1, 2, 3, 4} //和数组声明和像,但是[]没有指定长度。
    t.Log(&s1[0], len(s1), cap(s1))
    //s1 = append(s1, 5)    //使用append可以进行数据追加。为什么append还需要进行赋值?
}

结果:

 

切片如何实现可变长

func TestSliceGrowing(t *testing.T) {
    s := []int{}
    //t.Log(&s[0])  //没有赋值前,其实s并不存在
    t.Log(len(s), cap(s))
    for i := 0; i < 10; i++ {
        s = append(s, i)
        t.Log(&s[0], len(s), cap(s))
    }
}

结果:

 

cap增长规律:当len长度小于等于cap长度,cap不增长;当len长度等于cap长度,且有新元素加入,此时cap长度正常,增幅为当前cap长度的2倍。

  • 当cap不增长时,新增元素,其实就是往数组里面追加数据

  • 当cap增长时,新增元素,其实创建了一个新的存储空间,把旧的存储空间数据拷贝到新空间。这里就要考虑到切片自增长的代价。这也就是为什么append()需要赋值的原因

切片共享存储结构

slice是一个结构体,包含一个指针,指向了后端连续存储空间,此时如果是否可以做共享存储?多个slice,指向同一个存储空间。

如下场景:切片 year 表示一年十二个月,切片Q2从year中截断取[3,6)元素;切片summer从year中截断取[5,8)元素。此时三个切片其实共享了后端的存储,任何一个切片进行数据变更,每个共享数据的切片指向的该值都会发生变化。

func TestSliceShareMemory(t *testing.T) {
    year := []string{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}
    Q2 := year[3:6]
    t.Log(Q2, &Q2[0], len(Q2), cap(Q2))
    summer := year[5:8]
    t.Log(summer, &summer[0], len(summer), cap(summer))
    t.Log(&Q2[2])
​
    summer[0] = "Unknow"    //修改切片summer[0]数据的值
    t.Log(Q2)
    t.Log(summer)
    t.Log(year)
}

结果:

 

存储结构:

 

数组和切片比较

  1. 容量是否可以伸缩

    1. 数组不可以伸缩,切片可以

  2. 是否可以进行比较

    1. 数组比较需要是相同维数,相同长度;切片看似是数组,但是不能进行比较

代码:(切片不能比较)

func TestSliceComparing(t *testing.T) {
    a := []int{1, 2, 3, 4}
    b := []int{1, 2, 3, 4}
    if a == b { //invalid operation: a == b (slice can only be compared to nil)
        t.Log("equal")
    }
}

结果://invalid operation: a == b (slice can only be compared to nil)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Go语言中,切片(slice)是一个动态数组,它提供了对数组的部分或全部元素的访问和操作功能。切片的底层是通过数组实现的,但与数组相比,切片具有更强大的功能和灵活性。切片的底层实现原理是使用了一个结构体(runtime.slice)来表示切片的结构信息,包括指向底层数组的指针、切片的长度和容量等信息。切片的长度表示切片中实际存储的元素个数,而容量则表示切片底层数组的长度。切片可以根据需要动态扩容,当切片的长度超过了容量时,会重新分配更大的底层数组,并将原来的元素复制到新的底层数组中。这个过程是由Go语言的运行时系统自动完成的,不需要程序员手动操作。使用切片作为参数传递时,性能损耗很小,因为切片作为参数是传递的是一个结构体实例。切片作为参数具有比数组更强大的功能和灵活性,因此在Go语言中推荐使用切片而不是数组作为参数。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Golang切片的底层实现原理](https://blog.csdn.net/m0_72560813/article/details/129231704)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值