golang切片slice

切片不是数组,他是指向底层的数组
创建一般用make方法,第一个参数是指向的数组类型,第二个是存放元素的个数,第三个是存放容量,如果存放的个数超过容量,那么他就会从分配内存地址(容量在原来的基础上*2),len方法获取长度,cap获取容量
如果是简洁声明,不声明数组长度就是切片,譬如

s:=[] int{}//切片
a:=[10] int{1,2,3,4,5,6,7,8,9,10}//数组
c:=a[3,5]//切片c获取数组a下标3到5位元素值,包括3不包括5下标 
d:=a[3:]//下标3到a数组的长度
slice:= make(int[], 4, 6) 创建一个长度为4,容量为6的int类型slice

package main

import "fmt"
func testModifyElem(s []int) {
    s[0] = 1
    fmt.Printf("s inter address is %p \n", s)
    fmt.Println("s=", s)
}

func main()  {
    fmt.Println("------------------------ slice0 -------------------------")
    sa := make([]int, 10)
    fmt.Printf("sa address is %p \n", sa)
    fmt.Println("sa=", sa)
    testModifyElem(sa)
    fmt.Printf("post sa address is %p \n", sa)
    fmt.Println("post sa=", sa)
}


------------------------ slice0 -------------------------
sa address is 0xc0001220f0
sa= [0 0 0 0 0 0 0 0 0 0]
s inter address is 0xc0001220f0
s= [1 0 0 0 0 0 0 0 0 0]
post sa address is 0xc0001220f0
post sa= [1 0 0 0 0 0 0 0 0 0]


函数内部对slice某个元素的修改,会影响函数外面的slice。
函数内部的slice地址和函数外部的slice是一致的。

package main

import "fmt"

func testModifyElem2(s []int) {
    s[0] = 1
    fmt.Printf("函数内部 s inter address is %p \n", s)
    fmt.Println("函数内部 s=", s)
    s = append(s, 11)
    fmt.Printf("函数内部 s inter address(after append) is %p \n", s)
    fmt.Println("函数内部 s=(after append)", s)
}

func main() {
    fmt.Println("------------------------ slice0 -------------------------")
    sa := make([]int, 10)
    fmt.Printf("调用前 sa address is %p \n", sa)
    fmt.Println("调用前 sa=", sa)
    testModifyElem2(sa)
    fmt.Printf("调用后 post sa address is %p \n", sa)
    fmt.Println("调用后 post sa=", sa)
}

------------------------ slice0 -------------------------
调用前 sa address is 0xc0000a60f0
调用前 sa= [0 0 0 0 0 0 0 0 0 0]
函数内部 s inter address is 0xc0000a60f0
函数内部 s= [1 0 0 0 0 0 0 0 0 0]
函数内部 s inter address(after append) is 0xc0000d6000
函数内部 s=(after append) [1 0 0 0 0 0 0 0 0 0 11]
调用后 post sa address is 0xc0000a60f0
调用后 post sa= [1 0 0 0 0 0 0 0 0 0]

函数内部对slice某个元素的修改,会影响函数外面的slice。
如果函数内部对slice的append操作,不会影响到函数外部slice。
我们的slice len和cap都是10,函数内部的append会导致扩容,扩容之后,地址发生了变化,但是函数外部的slice地址并没有变化。这说明了golang的slice传递slice不是引用传递,而是值传递。

扩容策略

func main(){
    fmt.Println("------------------------ slice9 -------------------------")
    slice9 := []int{10, 20, 30, 40}
    newslice9 := append(slice9, 50)
    fmt.Printf("Before slice = %v, Pointer = %p, len = %d, cap = %d\n", slice9, slice9, len(slice9), cap(slice9))
    fmt.Printf("Before newSlice = %v, Pointer = %p, len = %d, cap = %d\n", newslice9, newslice9, len(newslice9), cap(newslice9))
    newslice9[1] += 10
    fmt.Printf("After slice = %v, Pointer = %p, len = %d, cap = %d\n", slice9, slice9, len(slice9), cap(slice9))
    fmt.Printf("After newSlice = %v, Pointer = %p, len = %d, cap = %d\n", newslice9, newslice9, len(newslice9), cap(newslice9))
    
}

输出 结果是:


------------------------ slice9 -------------------------
Before slice = [10 20 30 40], Pointer = 0xc000016100, len = 4, cap = 4
Before newSlice = [10 20 30 40 50], Pointer = 0xc00001c0c0, len = 5, cap = 8
After slice = [10 20 30 40], Pointer = 0xc000016100, len = 4, cap = 4
After newSlice = [10 30 30 40 50], Pointer = 0xc00001c0c0, len = 5, cap = 8

Go 中切片扩容的策略是这样的:

首先判断,如果新申请容量(cap)大于2倍的旧容量(old.cap),最终容量(newcap)就是新申请的容量(cap)
否则判断,如果旧切片的长度小于1024,则最终容量(newcap)就是旧容量(old.cap)的两倍,即(newcap=doublecap)
否则判断,如果旧切片长度大于等于1024,则最终容量(newcap)从旧容量(old.cap)开始循环增加原来的1/4,即(newcap=old.cap,for {newcap += newcap/4})直到最终容量(newcap)大于等于新申请的容量(cap),即(newcap >= cap)
如果最终容量(cap)计算值溢出,则最终容量(cap)就是新申请容量(cap)
注意:扩容扩大的容量都是针对原来的容量而言的,而不是针对原来数组的长度而言的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值