go切片

简介: go切片

Slice · Go语言圣经 (studygolang.com)Go 语言切片(Slice) | 菜鸟教程 (runoob.com)

slice构成

一个slice由三个部分构成:指针长度和容量

  • 指针指向第一个slice元素对应的底层数组元素的地址,要注意的是slice的第一个元素并不一定就是数组的第一个元素。
  • 长度对应slice中元素的数目;
  • 长度不能超过容量,容量一般是从slice的开始位置到底层数据的结尾位置。内置的len和cap函数分别返回slice的长度和容量。

示例

起因于如何使用append在一个切片中插入一个元素 最简单粗暴的办法就是再写一个

go

复制代码

func insertX(plaintext []byte, x byte) []byte {
    result := make([]byte, 0, len(plaintext)*2)
    for i := 0; i < len(plaintext)-1; i++ {
        result = append(result, plaintext[i])
        if plaintext[i] == plaintext[i+1] {
            result = append(result, x)
        }
    }
    // 添加最后一个字母
    result = append(result, plaintext[len(plaintext)-1])
    return result
}
func main() {
    plaintext := []byte("balloon")
    x := byte('x')
    result := insertX(plaintext, x)
    fmt.Println(string(result))
}

这个方法很不错,但是比较是学习切片,要上点难度

go

复制代码

func insertX(plaintext []byte, x byte) []byte {
    result := make([]byte, 0, len(plaintext))
    for i := 0; i < len(plaintext)-1; i++ {
        result = append(result, plaintext[i])
        if plaintext[i] == plaintext[i+1] {
            result = append(result, x)
        }
    }
    // 添加最后一个字母
    result = append(result, plaintext[len(plaintext)-1])
    return result
}
func main() {
    plaintext := []byte("balloon")
    x := byte('x')
    result := insertX(plaintext, x)
    fmt.Println(string(result))
}

append后面可以接受可变长切片...这里我们使用append函数来动态地向result切片中添加元素。首先,我们创建了一个容量为len(plaintext)的空切片result,然后在循环中使用append函数将元素逐个添加到result中。最后,我们将最后一个字母添加到result中,并返回结果。

切片的底层原理

字符串的切片操作和[]byte字节类型切片的切片操作是类似的。都写作x[m:n],并且都是返回一个原始字节序列的子序列,底层都是共享之前的底层数组,因此这种操作都是常量时间复杂度。x[m:n]切片操作对于字符串则生成一个新字符串,如果x是[]byte的话则生成一个新的[]byte。

因为slice值包含指向第一个slice元素的指针,因此向函数传递slice将允许在函数内部修改底层数组的元素。换句话说,复制一个slice只是对底层的数组创建了一个新的slice别名(§2.3.2)。

和数组不同的是,slice之间不能比较,因此我们不能使用 == 操作符来判断两个slice是否含有全部相等元素。

Slice底层实现 - 地鼠文档 (topgoer.cn)

切片扩容

新的切片和之前的切片已经完全不同了,因为新的切片更改了一个值,并没有影响到原来的数组,新切片指向的数组是一个全新的数组。并且 cap 容量也发生了变化。 Go 中切片扩容的策略是这样的:

  • 切片的容量小于 1024 个元素,于是扩容的时候就翻倍增加容量。上面那个例子也验证了这一情况,总容量从原来的4个翻倍到现在的8个。
  • 元素个数超过 1024 个元素,那么增长因子就变成 1.25 ,即每次增加原来容量的四分之一。

注意:扩容扩大的容量都是针对原来的容量而言的,而不是针对原来数组的长度而言的。

数组的容量已经达到了最大值,再想扩容, Go 默认会先开一片内存区域,把原来的值拷贝过来,然后再执行 append() 操作。这种情况丝毫不影响原数组。如果原数组还有容量可以扩容,所以执行 append() 操作以后,会在原数组上直接操作,所以这种情况下,扩容以后的数组还是指向原来的数组。


相关文章
|
5天前
|
Go 索引
Go 语言中同一 slice 上的切片其底层数组是否是同一个
Go 语言中同一 slice 上的切片其底层数组是否是同一个
26 0
|
5天前
|
安全 Go
这一次,带你深入浅出Go语言切片和数组
这一次,带你深入浅出Go语言切片和数组
39 0
|
5天前
|
Go 数据安全/隐私保护 索引
Go语言学习5-切片类型
【1月更文挑战第4天】本篇 Huazie 带大家了解 Go 语言的切片类型
44 2
Go语言学习5-切片类型
|
7月前
|
安全 Go 索引
Go切片循环就用range 有这一篇就够了
Go切片循环就用range 有这一篇就够了
118 0
|
5天前
|
存储 Java Go
Go 语言切片如何扩容?(全面解析原理和过程)
Go 语言切片如何扩容?(全面解析原理和过程)
14 2
|
5天前
|
Go 数据处理
Go杂记1-切片Slice作为函数参数那点事儿
Go杂记1-切片Slice作为函数参数那点事儿
7 0
|
5天前
|
存储 程序员 Go
【Go语言专栏】Go语言中的切片与映射
【4月更文挑战第30天】Go语言中的切片和映射是两种强大数据结构。切片是动态数组,长度可变,由指针、长度和容量组成,支持索引、切片、追加和复制操作。映射是键值对结构,基于哈希表实现,支持插入、删除、查找和遍历。两者都是Go语言处理数据的利器,理解其内部实现和用法能提升编程效率。
|
5天前
|
Go C++ 容器
【Go语言快速上手(三)】数组, 切片与映射
【Go语言快速上手(三)】数组, 切片与映射
|
5天前
|
存储 Go 索引
掌握Go语言:深入理解Go语言中的数组和切片,灵活处理数据的利器(16)
掌握Go语言:深入理解Go语言中的数组和切片,灵活处理数据的利器(16)
|
7月前
|
Go
Go 语言为什么建议 append 追加新元素使用原切片变量接收返回值?
Go 语言为什么建议 append 追加新元素使用原切片变量接收返回值?
24 0