首页 > 服务端语言 > Go 入门教程 > 27 Go 语言中的切片

本位主要介绍一下 Go 语言中 可变长度 的"数组"—— 切片(slice) 。数组有数组的用处,但是其不可变长度的特性,注定了在大多场景下不是很受欢迎。在大多数场景下我们都会选择更加灵活的 切片

1. 切片的创建

切片的声明方式和数组类似,写法上看就是声明一个没有长度的数组:var 切片名 []切片类型。其中切片类型可以是切片本身,也就是切片的切片,就构成了 多维 的切片。

切片在使用之前必须要 初始化 ,它没有零值。声明后它的值是 nil ,这是因为它的底层实现是一个指向数组的指针,在你给它存入一个数组的地址之前,它只能是 nil

代码示例

package main

import (
    "fmt"
)

func main() {
    var a []int
    fmt.Println("初始化前:", a)
    a = make([]int, 5, 10)
    fmt.Println("初始化后:", a)
    a[4] = 5
    fmt.Println("  赋值后:", a)
    a[5] = 6
    fmt.Println("赋值后:", a)
}
  • 第 8 行:声明一个int类型的切片。
  • 第 10 行:声明一个长度为5,切片容量为10的切片。其中容量可以不传,默认会和长度相等。长度为切片 真正有值 的位置,会 初始化零值
  • 第 12 行:给切片的第 5 个位置赋值。
  • 第 14 行:给切片的第 6 个位置赋值,但是切片的长度为5,所以会报越界的错误。

执行结果

图片描述

2. 切片的截取

切片之所以被叫做切片是有原因的,它可以从任意长度开始切,切到任意长度为止,然后这一段拿出来就是一个新的切片。切割形式为切片名(s)[起始下标(begin):结束下标(end):最大容量(max)]

Tips :截取到的切片包含起始下标(begin),不包含结束下标(end)。

切片截取形式表

操作 含义
s[begin?max] 截取切片s从begin到end的数据,构成一个容量为max-begin,长度为begin-end的切片。(用的不多)
s[begin:end] 截取切片s从begin到end的数据,构成一个容量和长度均为begin-end的切片。
s[begin:] 截取切片s从begin到最后的数据,构成一个容量和长度均为len(s)-end的切片。
s[:end] 截取切片s从0到最后的数据,构成一个容量和长度均为end-0的切片。

代码示例

package main

import (
    "fmt"
)

func main() {
    var a = []int{1, 2, 3, 4, 5}
    fmt.Println("a[1:3]=", a[1:3])
    fmt.Println("a[1:]=", a[1:])
    fmt.Println("a[:3]=", a[:3])
}
  • 第 8 行:直接定义一个值为 [1,2,3,4,5] 的切片, 切片长度和容量会根据切片的值自动生成 。例如本行代码定义的切片就是长度和容量均为5。
  • 第 9 行:取切片下标从1开始到3之前的值,生成新切片。
  • 第 10 行:取切片下标从1开始到最后的值,生成新切片。
  • 第 11 行:取切片下标从0开始到3的值,生成新切片。

执行结果

图片描述

3. 切片的追加

切片使用一个 Go 语言的内置函数append(切片,待添加的值),来进行切片末尾元素的追加。

代码示例

package main

import (
    "fmt"
)

func main() {
    var a = []int{1, 2, 3, 4, 5}
    a = append(a, 6)
    fmt.Println(a)
    a = append(a, 7, 8)
    fmt.Println(a)
    b := []int{9, 10}
    a = append(a, b...)
    fmt.Println(a)
}
  • 第 9 行:在切片 a 的末尾追加一个元素 6。
  • 第 11 行:在切片 a 的末尾连续追加两个元素 7 和 8。 append 中待添加的值可以是 多个 ,其中使用 , 隔开。
  • 第 14 行:在切片 a 的末尾追加切片 b。当 append 中 待添加的元素 是一个 数组或者切片 时,在其后面添加 ... 就可以全部追加到切片末尾。

执行结果

图片描述

4. 切片的长度和容量

在切片中可以使用len()获取切片中 元素的数量 ,也就是切片的长度。使用cap()可以获取切片 引用的数组的长度 ,也就切片的容量。切片的容量一般大于等于长度,容量会随着长度的增长而增长。

在初始化一个切片的时候其实时给切片引用了一个数组,然后容量就是这个数组的长度,然后如果切片的长度超过了切片的容量,它就会让切片引用一个容量更大数组来存放这些元素。

package main

import (
    "fmt"
)

func main() {
    var a = []int{1, 2, 3, 4, 5}
    fmt.Printf("a的地址%p,a的长度%d,a的容量%d\n", a, len(a), cap(a))
    a = append(a, 6)
    fmt.Printf("a的地址%p,a的长度%d,a的容量%d\n", a, len(a), cap(a))
    a = append(a, 7, 8)
    fmt.Printf("a的地址%p,a的长度%d,a的容量%d\n", a, len(a), cap(a))
    b := []int{9, 10, 11}
    a = append(a, b...)
    fmt.Printf("a的地址%p,a的长度%d,a的容量%d\n", a, len(a), cap(a))
}

执行结果

图片描述

从执行结果可以看到,在切片a每次添加的元素要 超过它的容量 时,它的地址就会发生 改变 ,其实就是让它引用了一个新的容量更大的数组。

5. 小结

本文主要介绍了切片的使用,有以下注意事项:

  • 切片在使用前需要初始化;
  • 切片的本质是一个指针数组,但是它的地址会随着长度超过容量而改变;
  • 在应用场景中一般都使用切片。
本文来自互联网用户投稿,不拥有所有权,该文观点仅代表作者本人,不代表本站立场。
访问者可将本网站提供的内容或服务用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯本网站及相关权利人的合法权利。
本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站,邮箱:80764001@qq.com,予以删除。
© 2023 PV138 · 站点地图 · 免责声明 · 联系我们 · 问题反馈