Go 切片内存分配

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go 切片内存分配相关的知识,希望对你有一定的参考价值。

参考技术A 切片是数组的抽象。 切片使用数组作为底层结构。 切片包含三个组件:容量,长度和指向底层数组的指针。
通过使用 append 或 copy 函数可以增加切片的容量。 append 函数可以为数组的末尾增加值,并在需要时增加容量。

当前储存空间存不下数据时,空间会以之前的空间数*2

比如:

定义 numbers 的数组长度为5 ,空间给他10,并追加数据到切片。

空间为10, 当我们再添加一个数据到切片时候,空间是多少了呢?

得到数据为20,和我们设想的一样。

切片中的数据是共用内存,也就是我们选区切片区间的某一个值,并且在这个小对象中进行数据的修改,会影响整个切片的值,在开发当中非常要注意这种。

举个例子:

取了一个first 和second 这两个数据重合的数据是2.

打印一下:

虽然在second 中修改了数据,但是影响到了大对象numbers 的数据,还有一个要注意的是,first 小对象,他的内存分配是5,second 的空间是4,这是为啥呢?原来,这样取的小对象切片,的空间是这个切片加上大对象末尾的值

开发中如果修改了其中的一个变量,但是又不想影响大对象,这个时候会傻掉。

那如何去获取一个和numbers 一样的数据,但是又不会影响numbers呢?

我们copy一份numbers

输出一下结果:

好,不懂在座的各位看懂了没有。没有影响的,通过copy 切片再去修改切片的值,是不会印象原切片的。

#yyds干货盘点#愚公系列2022年08月 Go教学课程 021-Go容器之切片操作

一、切片操作

1.什么是切片

切片和数组类似,都是数据集合。和数组不同的是,切片是一块动态分配大小的连续空间。

2.切片的定义

2.1 切片的格式

var 变量名 []T //T 表示切片类型。

相关案例:

package main

import "fmt"

func main()  
    // 声明整型切片
    var numList []int

    // 声明字符串切片
    var strList []string

    // 声明一个空切片,  表示已经分配内存,但是切片里面的元素是空的
    var numListEmpty = []int

    // 输出3个切片
    fmt.Println(numList, strList, numListEmpty)

    // 输出3个切片大小
    fmt.Println(len(numList), len(strList), len(numListEmpty))

    // 切片判定是否为空结果
    fmt.Println(numList == nil)
    fmt.Println(strList == nil)
    fmt.Println(numListEmpty == nil)

2.2 make() 函数定义元素

//T : 切片中元素的类型;
//size : 表示为这个类型分配多少个元素;
//cap : 预分配的元素数量,该值设定后不影响 size, 表示提前分配的空间,设置它主要用于降低动态扩容时,造成的性能问题。
make( []T, size, cap )

相关案例:

package main

import "fmt"

func main() 
    a := make([]int, 10)
    b := make([]int, 10, 20)

    fmt.Println(a, b)
    fmt.Println(len(a), len(b))

3.append() 函数增加元素

Go 语言中的内置函数 append() 可以为切片动态添加元素, 案例如下:

package main

import "fmt"

func main() 
    // 声明一个字符串类型的切片
    var strList []string

    // 循环动态向 strList 切片中添加 20 个元素,并打印相关参数
    for i := 0; i < 10; i++ 
        line := fmt.Sprintf("愚公 %d", i)
        strList = append(strList, line)

        fmt.Printf("len: %d, cap: %d, pointer: %p, content: %s\\n", len(strList), cap(strList), strList, strList[i])
    

    // 添加切片
    list := []string"愚公 10", "愚公 11"
    // list 后面的 ... 表示将 list 整个添加到 strList 切片中
    strList = append(strList, list...)

    fmt.Println(strList)

4.切片截取

slice [开始位置:结束位置]
  • slice 表示切片。
  • 开始位置和结束位置对应目标切片的下标。

相关案例:

package main

import "fmt"

func main() 

    // 添加切片
    list := []string"愚公 10", "愚公 11", "愚公 12"
    // list 后面的 ... 表示将 list 整个添加到 strList 切片中
    fmt.Println(list, list[1:2])

package main

import "fmt"

func main() 

    // 添加切片
    list := []string"愚公 10", "愚公 11", "愚公 12"
    // list 后面的 ... 表示将 list 整个添加到 strList 切片中
    fmt.Println(list, list[1:2], list[1:], list[:2], list[:])

  • 若不填写结束位置,如 list[1:], 则表示从下标 1 置到数组的结束位置。
  • 若不填写开始位置,如 list[:2],则表示从 0 到下标 2的位置。
  • 若开始位置和结束位置都不填写,如 list[:], 则会生成一个和原有切片一样的切片。

5.切片复制

copy( 原切片, 目标切片 []T) int

相关案例:

package main

import "fmt"

func main() 
    // 设置元素数量为 10
    const count = 10

    // 源分片
    list1 := make([]int, count)

    // 给源分片赋值
    for i := 0; i < count; i++ 
        list1[i] = i
    

    // 目标分片
    list2 := make([]int, count)

    // 将 srcSlice 分片的数据复制到 destSlice 中
    copy(list2, list1)

    fmt.Println(list1)
    fmt.Println(list2)

6.切片删除

Go 语言中并没有提供特定的函数来删除切片中元素,可以利用append来实现切片拼接来删除。

package main

import "fmt"

func main() 
    // 声明一个字符串类型的切片
    arr := []string"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"

    // 打印删除位置之前和之后的元素, arr[:index] 表示的是被删除元素的前面部分数据,arr[index+1:] 表示的是被删除元素后面的数据
    fmt.Println(arr[:1], arr[2:])

    // 将删除点前后的元素拼接起来
    arr = append(arr[:1], arr[2:]...)

    fmt.Println(arr)

以上是关于Go 切片内存分配的主要内容,如果未能解决你的问题,请参考以下文章

Python 切片分配内存使用情况

Cython:将单个元素分配给多维内存视图切片

go语言学习笔记 — 基础 — 高级数据类型 — 数据容器 — 切片:切片内部结构

图解Go语言内存分配

Go 内存分配

Go 内存分配