golang 定义一个空切片_深入理解 golang 切片机制(理)

切片总是要有一个交代的,来看看这段代码code

package main

import (

"fmt"

"unsafe"

)

type Slice struct {

ptr unsafe.Pointer // Array pointer

len int // slice length

cap int // slice capacity

}

// 因为需要指针计算,所以需要获取int的长度

// 32位 int length = 4

// 64位 int length = 8

var intLen = int(unsafe.Sizeof(int(0)))

func main() {

s := make([]int, 10, 20)

// 利用指针读取 slice memory 的数据

if intLen == 4 { // 32位

m := *(*[4 + 4*2]byte)(unsafe.Pointer(&s))

fmt.Println("slice memory:", m)

} else { // 64 位

m := *(*[8 + 8*2]byte)(unsafe.Pointer(&s))

fmt.Println("slice memory:", m)

}

// 把slice转换成自定义的 Slice struct

slice := (*Slice)(unsafe.Pointer(&s))

fmt.Println("slice struct:", slice)

fmt.Printf("ptr:%v len:%v cap:%v \n", slice.ptr, slice.len, slice.cap)

fmt.Printf("golang slice len:%v cap:%v \n", len(s), cap(s))

s[0] = 0

s[1] = 1

s[2] = 2

// 转成数组输出

arr := *(*[3]int)(unsafe.Pointer(slice.ptr))

fmt.Println("array values:", arr)

// 修改 slice 的 len

slice.len = 15

fmt.Println("Slice len: ", slice.len)

fmt.Println("golang slice len: ", len(s))

}

看出什么来了么?

储备知识:

unsafe.Pointer 类似于c语言中的void*

unsafe.Pointer所占空间 = int 类型所占字节数

结论:

slice的结构等同于Slice结构体

// 每次cap改变,指向array的ptr就会变化一次

s := make([]int, 1)

fmt.Printf("len:%d cap: %d array ptr: %v \n", len(s), cap(s), *(*unsafe.Pointer)(unsafe.Pointer(&s)))

for i := 0; i < 5; i++ {

s = append(s, i)

fmt.Printf("len:%d cap: %d array ptr: %v \n", len(s), cap(s), *(*unsafe.Pointer)(unsafe.Pointer(&s)))

}

fmt.Println("Array:", s)

替换上面的主程序,你发现了什么呢?

每次append,地址都会发生变化 ,说明当cap不够的时候,会产生复制操作。

实际go在append的时候放大cap是有规律的。在 cap 小于1024的情况下是每次扩大到 2 * cap ,当大于1024之后就每次扩大到 1.25 * cap 。所以上面的测试中cap变化是 1, 2, 4, 8

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值