27、Go 复合数据类型 - 内置函数 make & 切片中使用 make

作者: 温新

分类: 【Go基础】

阅读: 905

时间: 2023-08-29 16:04:20

hi,我是温新

make 函数用途

内置函数 make() 用于为 slicemapchannel 类型分配内存和初始化一个对象。

make 函数语法

// 格式
make(type,len,cap)

1、type:数据类型,必填参数。type 的值只能是 slice、map、channel;

2、len:数据类型实际占用的内存空间长度,slice 是必填参数,map 和 channel 是可选参数;

3、cap:容量,为数据类型提前预留的内存空间长度,是一个可选参数。

make 三种不同用法

// 方式一
make(map[string|string])
// 方式二
make([]int, 2)
// 方式三
make([]int, 2, 4)

方式一:只传类型,不指定实际占用的内存空间和提前预留的内存空间,适用于 map 和 channel;

方式二:指定实际占用的内存空间为 2,不指定提前预留的内存空间;

方式三:指定实际占用的内存空间为 2,指定提前预留的内存空间 为 4。

为什么要提前预留空间?

make() 使用的是动态数组算法,一开始向操作系统申请一小块内存 cap,等到 cap 被 len 占满后就需要扩容,而扩容就是动态数组再去向操作系统申请当前长度的两倍的内存,然后将旧数据复制到新的内存空间中。

切片中使用 make

切片中为什么使用 make?

看一个案例

package main

import "fmt"

func main() {
    // 声明一个切片
    var s []int
    fmt.Println(s) // []
    s[0] = 100     // 报错
    fmt.Println(s)
}

1、声明一个切片,没有赋值,此时内存中并没有开辟一个底层数组出来;

2、因此它打印出来为 []

3、对其进行赋值,由于没有开辟出底层数组,因此会报错。

那么,可以这样理解,有一棵树,我用纸写是椅子这个两个,然后贴在树上。如果你要真坐上去,可自然就没有法做了,因为树还没有被加工成椅子。

使用 make 函数相对于就是对这棵树进行加工成椅子,然后就可以坐了。

使用 make 函数

package main

import "fmt"

func main() {
    // make 创建一个指定长度和容量的切片
    var sli = make([]int, 3, 6)
    fmt.Println(sli) // [0 0 0]

    // 对指定元素赋值
    sli[2] = 100
    // 追加元素
    sli = append(sli, 200)
    fmt.Println(sli)
}

1、使用 make 创建一个长度为 3 ,容量为 6 的切片,此时,会在底层开出一个数组,其容量为 6,但长度为 3,也就是存储的实际值有 3 个,默认为 0 ;

2、因此打印的时候,只会打印出 3 个 0;

3、修改指定元素的值为 100;

4、追加一个元素到切片中,由于提前开辟了预留容量,因此不会动态扩容。

下面是动态扩容案例:

package main

import "fmt"

func main() {
    sli := make([]int, 2)
    sli[0] = 10
    sli[1] = 20
    fmt.Printf("长度=%d 容量=%d sli=%v\n", len(sli), cap(sli), sli)
    // 追加元素,动态扩容
    sli = append(sli, 30, 40, 50)
    fmt.Printf("长度=%d 容量=%d sli=%v\n", len(sli), cap(sli), sli)
}

输出结果如下

长度=2 容量=2 sli=[10 20]
长度=5 容量=6 sli=[10 20 30 40 50]
请登录后再评论