【Go进阶—数据结构】Slice

简介: slice 又称动态数组,依托数组实现,但比数组更灵活,在 Go 语言中一般都会使用 slice 而非 array。

特性
声明和初始化 slice 的方式除了从数组中直接切取外,主要还有以下几种:变量声明、字面量声明、使用内置函数 new() 和 make()。使用变量声明和 new() 函数后的 slice 的值为 nil,对其使用 append() 追加元素时会导致异常,一般推荐使用 make() 函数来初始化。

实现原理
数据结构
源码 src/runtime/slice.go:slice 定义了 slice 的数据结构:

type slice struct {
    array unsafe.Pointer // 底层数组指针
    len   int            // 长度
    cap   int            // 容量
}

相关操作
创建
当我们使用 make() 创建 slice 时,可以同时指定长度和容量,底层会分配一个数组,数组的长度即容量。

例如,slice := make([]int, 5, 10)所创建的 slice,结构如下所示:

1.png

扩容
向 slice 追加元素时,如果 slice 的容量不足以容纳追加的元素时,将会触发扩容。扩容实际上是重新分配一块更大的内存,将原 slice 拷贝进新 slice,再将数据追加进去。这也是为什么我们经常能见到类似于 s := append(s, 1) 这种写法的原因。

扩容时容量的变化遵循以下基本规则:

原 slice 容量小于 1024,则新 slice 的容量扩大为原来的 2 倍;
原 slice 容量大于等于 1024,则 新 slice 的容量扩大为原来的 1.25 倍。
不过,实际过程中还会综合考虑元素的类型及其内存分配策略,在该规则的基础上做一些微调(如内存对齐)。

下面有一段代码示例,观察函数的输出,结合本部分内容,可以很好地明白扩容的内部机制:

package main

import "fmt"

func SliceRise(s []int) {
    s = append(s, 0)
    for i := range s {
        s[i]++
    }
}

func main() {
    s1 := []int{1, 2}
    s2 := s1
    s2 = append(s2, 3)
    SliceRise(s1)
    SliceRise(s2)
    fmt.Println(s1, s2)
}

拷贝
拷贝两个 slice 时,会将源 slice 的元素逐个拷贝到目的 slice 指向的底层数组中,拷贝数量取决于两个 slice 长度的较小值。例如长度为 10 的 slice 拷贝到长度为 5 的 slice 中时,只会拷贝 5 个元素,过程中并不会触发扩容。

一些Tips
我们常说 slice 是所谓的引用类型,主要就是因为它的结构内部含有底层数组的指针,因此在函数内部修改 slice 中的元素的话,外部变量也会受到影响。

我们可以使用 a[low:high] 表达式切取字符串,此时会产生新的字符串,用这个方法可以快速截取字符串。

如果我们是从字符串或数组上切取 slice 的话,表达式 a[low:high] 需满足: 0 <= low <= high <= len(a),如果不满足则会触发 panic。

但是如果切取对象是另一个 slice 的话,low 和 high 的最大取值就不是 a 的长度,而是 a 的容量。在实际使用中,我们需要注意这一点。

如果你想开发小程序或者了解更多小程序的内容,可以通过专业开发公司,来帮助你实现开发需求:厦门在乎科技-专注厦门小程序开发公司、APP开发、网站开发、H5小游戏开发

相关文章
|
4月前
|
存储 安全 Java
Go 基础数据结构的底层原理(slice,channel,map)
Go 基础数据结构的底层原理(slice,channel,map)
53 0
|
6月前
|
编译器 程序员 测试技术
详解动态内存管理【malloc/calloc/realloc/free函数/柔性数组】【C语言/进阶/数据结构基础】
详解动态内存管理【malloc/calloc/realloc/free函数/柔性数组】【C语言/进阶/数据结构基础】
173 0
|
5月前
|
Cloud Native Go
GO语言初始化数据结构的方法你知道吗?
GO语言初始化数据结构的方法你知道吗?
|
1月前
|
存储 Go
关于 go 语言里的 slice 数据结构
关于 go 语言里的 slice 数据结构
15 0
|
2月前
|
Java 测试技术 Go
Go语言标准库进阶应用与最佳实践:提升代码质量与性能
【2月更文挑战第8天】在掌握了Go语言标准库的基础应用后,如何进一步发掘其潜力,提升代码质量和性能,是每位Go语言开发者所关心的问题。本文将探讨Go语言标准库的进阶应用与最佳实践,包括标准库与其他库的协同使用、性能优化与内存管理、错误处理与异常捕获、标准库在实际项目中的应用案例,以及推荐的最佳实践与编程规范。通过深入了解这些内容,开发者能够更好地利用Go语言标准库,提升代码质量与性能,构建出更加高效、可靠的软件应用。
|
2月前
|
存储 安全 Java
Go Slice的底层实现原理深度解析
在Go语言的世界里,切片(Slice)是一种极其重要的数据结构,它以其灵活性和高效性在众多编程场景中扮演着核心角色。本文将深入探讨Go切片的底层实现原理,通过实例和源码分析,带你领略Go语言设计之美。
|
6月前
|
自然语言处理 编译器 Linux
超详细!通晓Go语言编译运行 你需要这篇攻略 | 进阶指南
超详细!通晓Go语言编译运行 你需要这篇攻略 | 进阶指南
448 0
超详细!通晓Go语言编译运行 你需要这篇攻略 | 进阶指南
|
3月前
|
设计模式 JSON Go
Go语言进阶,提升必备
Go语言进阶,提升必备
34 0
|
3月前
|
Go
Go语言Channel进阶:巧妙运用超时机制
Go语言Channel进阶:巧妙运用超时机制
73 0
|
3月前
|
缓存 NoSQL Java
Redis进阶-核心数据结构进阶实战
Redis进阶-核心数据结构进阶实战
55 0