白话go语言(一):slice的创建

2019-05-11  本文已影响0人  Top2_头秃

直奔主题,我们从源码分析开始,一步一步往下走,慢慢得到我们想知道的内容

slice的源码位于 runtime包的slice.go文件中,slice结构体

type slice struct {
      // go跟c一样是一个强类型的语言,这个unsafe.Pointer 可以看成是C中的(void*)
        // 一个(void)类型的指针array,指向了底层的数组结构
    array unsafe.Pointer 
    len   int // slice中元素的个数
    cap   int // 底层数组的容量大小
}

makeslice的源码

提前说一下 uintptr类型的含义,uintptr是指uinptr指针所指内容的大小。通俗的说就是如果指针指向的内容是char类型 uintptr就是一个字节,指向的是一个int类型 uintptr就是4个字节大小。
类似于c语言中的 int *a; sizeof(*a)


func makeslice(et *_type, len, cap int) unsafe.Pointer {
        // 计算要分配的堆内存的大小,并返回是否溢出。
        // 要分配的堆内存大小=实现slice要用到的底层数组大小cap*一个slice(中数据类型)的大小、
    mem, overflow := math.MulUintptr(et.size, uintptr(cap))
        // 如果内存溢出,活着要分配内存大于可分配的最大内存,或者slice元素个数比底层实现该slice结构的数组容量还要大
    if overflow || mem > maxAlloc || len < 0 || len > cap {
              /* 如果没有那么大的内存可分配 或者 cap<len,
那么就分陪len个元素的容量并看一下是否为超过可分配内存限制
*/
        mem, overflow := math.MulUintptr(et.size, uintptr(len))
        if overflow || mem > maxAlloc || len < 0 {
            panicmakeslicelen() // 抛出一个“len out of range”pannic
        }
        panicmakeslicecap() //抛出一个“cap out of range” panic
    }
        // 分配内存,这个函数太复杂了,我们暂时不分析
        // 返回锁分配的内存的收地址的指针
    return mallocgc(mem, et, true)
}

该函数位于src/builtin 包中,由于go内联函数我们看不到函数的实现体,我也不知道为啥看不到,反正是听一位大佬说,内联函数无法看到实现体,可能是代码太烂了,不忍心让人看吧,谁也说不准 😄

func make(t Type, size ...IntegerType) Type

我们就只分析函数名称和返回类型吧。
这个函数提供了两个参数
t:Type类型(这里的Type只能是map slice 或者chan)
三个点表示可以有任意多个参数,这些参素的类型是IntegerType类型
返回类型就是t对应的类型。

-----------------------我是分割线------------------------

源码也看了,现在我们分析一下make一个slice的过程,同时意淫以下那个 因为代码太烂而不忍心让大家看到实现体的 make函数到底干了哪些见不得人的勾当。

创建一个slice var s []int = make([]int,5,10)

  1. 第一个参数t 是一个int类型的数组,那第二个和第三个又是什么意思呢。
  2. 我们猜测(其实就是)内敛函数make其实调用了makeslice,
    3.通过前面的makesslice源码分析,第二个参数5其实对应的slice结构体的len,第三个参数10对应的就是slice结构体的cap
    4 在make函数中 我们初始化了slice 结构体中的这两个值,同时makesslice返回的指针初始化了slice结构体的array

看到这里,大家应该也能明白为啥slice只能由make创建,因为只有make中能初始化slice结构体中的这两个变量😄

上一篇 下一篇

猜你喜欢

热点阅读