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() 操作以后,会在原数组上直接操作,所以这种情况下,扩容以后的数组还是指向原来的数组。


相关文章
|
16天前
|
存储 Go
|
16天前
|
Java Go 数据处理
go语言使用切片而非数组
【10月更文挑战第18天】
9 1
|
5月前
|
Go
Go 中使用切片来实现动态数组的功能
Go 中使用切片来实现动态数组的功能
|
15天前
|
Go
|
5月前
|
Go
go语言数组与切片
go语言数组与切片
|
29天前
|
存储 安全 Go
Go语言切片:从入门到精通的深度探索###
本文深入浅出地剖析了Go语言中切片(Slice)这一核心概念,从其定义、内部结构、基本操作到高级特性与最佳实践,为读者提供了一个全面而深入的理解。通过对比数组,揭示切片的灵活性与高效性,并探讨其在并发编程中的应用优势。本文旨在帮助开发者更好地掌握切片,提升Go语言编程技能。 ###
|
2月前
|
Go 索引
Go to Learn Go之切片
Go to Learn Go之切片
28 1
|
2月前
|
编译器 Go 索引
Go数组、多维数组和切片(动态数组),及常用函数len(),cap(),copy(),append()在切片中的使用
本文介绍了Go语言中数组、多维数组和切片(动态数组)的基本概念和操作,包括数组的定义、初始化、访问,多维数组的定义和访问,以及切片的创建、使用和扩容。同时,还讲解了切片中常用的函数len()、cap()、copy()和append()的使用方法。
|
3月前
|
Go
Go 1.21的新特性: 切片和映射
Go 1.21的新特性: 切片和映射
|
3月前
|
存储 Go
go 切片长度与容量的区别
go 切片长度与容量的区别