Golang Slice


2022 年 1 月 8 日, 学习 eTutorial
2284

在本教程中,我们将讨论 Go 切片数据类型,它属于复合类型的引用数据类型。在这里,您将了解 Golang 中切片到底是什么,它们在 Golang 中的定义和声明语法,以及 Golang 中使用的复制、追加、移动函数等。

Golang 中的切片是什么?

切片是一种引用类型数据结构,表示现有或底层数组中相同类型元素序列的一部分。切片指的是现有数组的一部分或一个片段。与数组一样,切片不拥有自己的数据,它只提供对数组中特定数据/元素片段的引用。

  • 切片是灵活的,大小是动态的,即切片的大小可以调整;它们不像数组那样是固定大小的。
  • 与数组不同,切片不存储任何数据。
  • 切片用于表示底层数组的一部分。
     

让我们通过一个简单的数组表示法来更轻松地理解切片概念。

GO : Slice

上图显示了一个数组“A”,索引为 0、1、2...9。每个数组索引存储一些字符串类型的元素。例如,索引为 0 的数组 A[0] 包含“LET”,A[1] 包含“US”等...(为了更好地理解数组,请参考数组教程)。

现在让我们了解切片如何与数组协同工作。数组 A 将被分成两个切片。A 的两个切片 Slice 1 和 Slice 2 构成底层数组的子集。

GO : Slice

如何在 Golang 中声明和初始化切片?

切片的声明与数组类似。与数组相比,唯一的例外是切片的大小不需要预先指定。

例如,切片声明中的方括号 [ ] 保持为空,而在数组的情况下,方括号内指定了一些值,如 [5]、[7] 来初始化数组大小。根据切片的要求,切片的大小会相应地扩展和压缩。

语法

空方括号 [ ],后跟数组教程中讨论的任何声明类型。


[ ] arrDec
 Or 
[ ] arrDec{ }
Or
[ ] arrDec{value1, value 2, value 3 …………..value m}

在上述语法中,arrDec 表示所选数组声明的类型。

GO : Slice

Golang 程序演示如何使用切片字面量和简写符号创建切片


package main
import "fmt"
 
func main() {
 
    // Creating a slice
    // using the var keyword
    var slice1 = []string{"learn", "e", "tutorials"}
 
    fmt.Println(" Slice 1:", slice1)
 
    // Creating a slice
    //using shorthand declaration
    slice2 := []int{ 67, 67,56,98, 43 }
    fmt.Println(" Slice 2:", slice2)
    }

输出


Slice 1: [learn e tutorials]
Slice 2: [67 67 56 98 43]

Golang 切片中的 Make () 函数

Golang 中的 make 函数会创建一个新的切片。它是一个内置函数。

  •   语法用 make () 函数表示,括号内包含参数类型、长度和容量。容量是可选的。           
  • make () 分配底层数组,其大小等于提供的容量。
  • make() 返回的切片指向数组的那一部分。

语法


make([]arrDec, len, cap) []arrDec

使用 make() 创建切片程序


package main
import "fmt"

func main() {
   // Creating slice using make function
   A := make([]string, 5)  
   //initially empty
    fmt.Println("array A is: ", A) 
   //assigning values to slice array
    A[0] = "Golang"
    A[1] = "in"
    A[2] = "learn"
    A[3] = "e"
    A[4] = "tutorials"

    fmt.Println("slice created using make(): ", A)
}

输出


array A is:  [    ]
slice created using make():  [Golang in learn e tutorials]

解释: 

  • 使用 make 函数创建了一个字符串类型的切片,通过将大小设置为 5,使其容量能够容纳 5 个元素。 
  • 切片创建后,它是空的,没有值。会设置默认值。如果是字符串,则为空格,如果是整数,则为 0。
  • 在下一步中,将新值分配给切片。
     

如何在 Golang 中切片数组/创建切片?

  • 切片是通过从底层或现有数组中切分一个子集来创建的。
  • 为了切分,我们需要在方括号内定义要切分的元素范围。
  • 该范围定义了切片开始的下限到上限,在这种情况下,排除了最后一个元素。
  • 下限的默认值为零,上限的切片长度也为零。
  • 示例:切片 1 在范围 [2:6] 内,不包括第 6 个元素。下面的给定程序解释了相同的概念。
     

Golang 程序演示切片的创建


package main
import "fmt"
 
func main() {
 
    // Creating an array
    A:= [10]string{"Let", "us", "learn", "Go",
                         "programming", "language", "with","learn ","e","tutorials"}
 
    // Display array
    fmt.Println("Array A:", A)
 
    // Creating a slice
    slice1:= A[2:6] // start from index 2 till 5
    
    slice2 :=A[:2] //start from index 0 till 1 excludes index 2
    
    slice3 := A[7:] //start from 7 till ending index
    
    slice4 := A[:]
 
    // Display slice
    fmt.Println("Slice 1 is :", slice1)
    fmt.Println("Slice 2 is :", slice2)
    fmt.Println("Slice 3 is :", slice3)
    fmt.Println("Slice 4 is :", slice4)
}

输出


Output
Array A: [Let us learn Go programming language with learn  e tutorials]
Slice 1 is : [learn Go programming language]
Slice 2 is : [Let us]
Slice 3 is : [learn  e tutorials]
Slice 4 is : [Let us learn Go programming language with learn  e tutorials]

什么是切片内部结构/切片组件?

切片内部结构是构成切片的组件。切片在内部表示为指向数组的指针,以及其长度和容量。我们知道切片是数组的一个片段,具有这三个组件,因此可以用以下语法概括。

  1. 指针
  2. 长度
  3. 容量

type Slice struct {
    array unsafe.Pointer
    cap   int
    len   int
}

切片中的指针是什么?

指针指向数组中切片的初始元素。在给定示例中,切片 1 包含元素

[“LEARN”,” GO”,” PROGRAMMING”,” LANGUAGE]

GO : Slice

这里初始或起始元素是索引为 2 的 learn,所以指针指向该位置。因此指针设置为 2。

如何查找切片的长度?

切片的长度是切片中元素的数量。len()函数用于确定切片的长度。在下面给定的切片1中,从开头算起共有4个元素。因此长度设置为4。

切片1 ---- > [“LEARN’ “Go”,” PROGRAMMING” “LANGUAGE “]

len(slice1) 返回切片 1 中存在的元素数量,即 len(slice1) 调用返回值为 4。

Golang 中切片的容量是多少?

切片的容量是底层数组中元素的最大数量。切片中的 `cap()` 函数用于确定切片的容量。在下面的示例中,从 slice1 元素的开头开始计数,直到底层数组的末尾。

GO : Slice

因此,从切片 1 索引的开头到数组的末尾位置计数,表示上述切片的容量,它返回一个整数值 8。它可以表示为 **cap(slice) = 8**。

下图描述了切片 1 的内部组件,其中指针指向数组地址 2,片段长度为 4,切片 1 的容量为 8,因为切片 1 是数组 A 的一个片段,实际大小为 10(0,1,2.....9 索引),其中从 2 到 5 的索引形成切片 1 的片段,连同从 6 到 9 的剩余索引共同构成总容量,即容量等于 8。(与上面讨论的示例相关)

GO : Slice

让我们使用 Golang 来理解上面讨论的 len()cap() 函数。我们讨论的相同描述在下面的 Go 程序中进行了编码。

Golang 程序演示切片 len()、cap() 的工作原理


package main
import "fmt"
 
func main() {
 
    // Creating an array
    A:= [10]string{"Let", "us", "learn", "Go",
                         "programming", "language", "with","learn ","e","tutorials"}
 
    // Display array
    fmt.Println("Array:", A)
 
    // Creating a slice
    slice1:= arr[2:6]   //slicing array
 
    // Display slice
    fmt.Println("Slice 1 is :", slice1)
 
    // Display length of the slice
    fmt.Printf("Length of the slice 1: %d", len(slice1))
 
    // Display the capacity of the slice
    fmt.Printf("\nCapacity of the slice 1: %d", cap(slice1))
}

输出


Output
Array A: [Let us learn Go programming language with learn  e tutorials]
Slice 1 is : [learn Go programming language]
Length of the slice 1: 4
Capacity of the slice 1: 8

如何向切片追加元素?

Append () 函数是切片中的一个内置函数,用于向切片追加元素。
另外,append () 允许扩展切片的大小。

向切片追加的程序


package main
import "fmt"

func main() {
// slice creation using make()
  A := make([]string, 3)
//dispplays initial slice values
    fmt.Printf("slice:%v; len: %d; cap: %d \n", A, len(A), cap(A))

    fmt.Println("---------------------------")
//performs appending values to slice A
    A = append(A, "Go")
    A = append(A, "Lang")
    A = append(A, "in")
    A = append(A, "learn", "e", "tutorials")
//display slice after insertion
    fmt.Printf("slice: %v; len: %d; cap: %d \n", A, len(A), cap(A))
}

输出


slice:[  ]; len: 3; cap: 3 
---------------------------
slice: [   Go Lang in learn e tutorials]; len: 9; cap: 12 

  • 在上面的示例中,使用 make () 函数在切片中声明了三个元素。空切片是字符串类型,长度和容量为 3。
  • 六个元素 Go Lang in learning e tutorials 被追加到切片 A 中,这将切片扩展到长度 9,容量为 12。

如何在切片中复制?

Copy() 函数是一个内置函数,允许将元素从一个切片(源切片)复制到另一个切片(目标切片)。

复制切片的程序


package main
import "fmt"

func main() {
// slice creation using make()
  A := []string {"Go", "lang"}
  B :=make([]string,len(A))
//displays initial slice values
    fmt.Printf("Initial slice A:%v; len: %d; cap: %d \n", A, len(A), cap(A))

    fmt.Println("---------------------------")

   copy1 := copy(B,A)
//display slice after COPYING
   
    fmt.Printf("%d elements copied\n", copy1)
    fmt.Printf("slice after copying to B: %v; len: %d; cap: %d \n", B, len(B), cap(B))
}

输出


Initial slice A:[Go lang]; len: 2; cap: 2 
---------------------------
2 elements copied
slice after copying to B: [Go lang]; len: 2; cap: 2 

在上面的程序中,使用 copy() 函数将切片 A 中的复制切片声明为字符串类型的切片 B。

Golang 切片中的迭代?

在切片中,for 循环用于迭代切片元素。


package main

import "fmt"

func main() {

   tutorial := []string{"Go", "Programming", "language", "in", "learn", "e","tutorials"}

    for a, tutorial := range tutorial {

        fmt.Println(a, tutorial)
    }
}

输出


0 Go
1 Programming
2 language
3 in
4 learn
5 e
6 tutorials

数组与切片的区别

序号 数组 切片
1 数组存储相同类型的元素序列 切片不存储任何数据
2 数组大小固定 切片灵活可调整大小
3 数组在 Go 中使用较少 切片在 Go 中最常用
4 数组副本指向不同的底层数据 切片副本指向相同的底层数据