Go切片与技巧(附图解)

本文深入探讨了Go语言中的切片,包括切片的创建(如变量声明、切片字面量、make创建、使用new以及从数组/切片截取)、切片操作(如append)和切片表达式。文章还详细介绍了切片的各种技巧,如Copy、Delete、Insert、Filter、Shuffle等,旨在帮助开发者更好地理解和利用Go切片的特性。
摘要由CSDN通过智能技术生成

以下文章原文来自公众号『太白技术』,欢迎关注,转载请联系公众号。

你好,我是太白,今天和你聊聊Go语言的切片(Slice)以及它的一些技巧。

1 前言

切片是Go语言中最多被使用的数据结构之一。本文将介绍切片的创建、操作、表达式以及使用的技巧。

2 数组

slice类型是建立在 Go 的数组类型之上的抽象,因此要理解 slice,我们必须首先理解数组。

先看一段代码:

    var a [4]int // 数组类型: 定义指定长度和元素类型
    a[0] = 1     // 数组a的第一个索引的值设置为1
    i := a[0]
    fmt.Println(i)    // 输出:1, 说明已经设置成功
    fmt.Println(a[1]) // 输出:0,说明数组不需要显式初始化,其元素本身为零
    fmt.Println(a[4]) // 报错:invalid array index 4 (out of bounds for 4-element array)

(代码来自 Go Slices: usage and internals

说明:

  • 1、代码中 var a [4]int 完成了数组的初始化,表示一个由四个整数组成的数组。
  • 2、默认值为0。当我们打印a[1]的时候输出0。
  • 3、设置数组索引的值,可以直接指定下标的索引进行赋值,例子中是a[0] = 1
  • 3、Go数组的索引和其他语言一样,从0开始,数组的大小是固定的,上面例子中最大是4的的大小,所以下标索引最大是3,所以当我们访问a[4]会报数组越界的错误。

Go的数组是值类型。不像C语言数组变量是指向第一个元素的指针,所以当我们把数组变量传递或者赋值的时候,其实是做copy的操作。比如下面的例子a赋值给b,修改a中的元素,并没有影响b中的元素:

    a := [2]string{
   "johnny", "太白技术"} // 长度`2`,可以改成`...`,编译器会自动计算数组的长度
    b := a
    a[0] = "xujiajun"
    fmt.Println(a) // 输出:[xujiajun 太白技术]
    fmt.Println(b) // 输出:[johnny 太白技术]

为了避免复制,你可以传递一个指向数组的指针,例如:

func double(arr *[3]int) {
   
    for i, num := range *arr {
   
        (*arr)[i] = num * 2
    }
}
a := [3]int{
   1, 2, 3}
double(&a)
fmt.Println(a) // [2 4 6]

(代码参考 Effective Go

3 切片的创建

由于数组需要固定长度,很多时候不是很灵活,而切片更灵活、更强大。切片包含对底层数组的引用,如果将一个切片分配给另一个切片,则两者都引用同一个数组。

切片底层的数据结构(src/runtime/slice.go):

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

切片的类型规范是[]T,其中T是切片元素的类型。与数组类型不同,切片类型没有指定长度

创建切片有多种方式:变量声明切片字面量make创建new创建从切片/数组截取

1、变量声明
    var s []byte

这种声明的切片变量,默认值是nil,容量和长度默认都是0。

    var x []byte
    fmt.Println(cap(x))   // 0
    fmt.Println(len(x))   // 0
    fmt.Println(x == nil) // true
2、切片字面量

当使用字面量来声明切片时,其语法与使用字面量声明数组非常相似:

a := []string{
   "johnny", "太白技术"} // 这是切片声明,少了长度的指定
b := [2]string{
   "johnny", "太白技术"} // 这是数组声明,多了长度的指定
3、make创建:

除了上面创建方式外,使用内置函数make可以指定长度容量来创建(具体函数:func make([]T, len, cap) []T)

其中 T 代表要创建的切片的元素类型。该make函数采用类型、长度和可选容量。调用时,make分配一个数组并返回一个引用该数组的切片。

首先看下空切片:

    y := make([]int, 0)
    fmt.Println(cap(y))   // 0
    fmt.Println(len(y))   // 0
    fmt.Println(y == nil) // false

下面这个例子中创建了长度为5,容量等于5的切片

    var s []byte
    s = make([]byte, 5, 5) // 指定了长度和容量
    fmt.Println(s) // 输出:[0 0 0 0 0]

当容量参数被省略时,它默认为指定的长度:

s := make([]byte, 5)
fmt.Println(s) // 输出也是 [0 0 0 0 0]

内置len和cap函数检查切片的长度和容量:

    fmt.Println(len(s)) // 5
    fmt.Println(cap(s)) // 5
4、使用new

使用new创建的切片是个nil切片。

    n := *new([]int)
    fmt.Println(n == nil) // true
5、从切片/数组截取

切片可以基于数组和切片来创建。这边会用到切片表达式,3.3会详细说明。

    n := [5]int{
   1, 2, 3, 4, 5}
    n1 := n[1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值