开放的编程资料库

当前位置:我爱分享网 > Go教程 > 正文

如何在Golang中使用切片

Go切片教程展示了如何在Golang中使用切片。

数组是单一数据类型元素的集合。数组包含固定数量的元素,并且不能增长或收缩。数组的元素通过索引访问。

slice是对数组元素的动态大小、灵活的视图。切片可以在底层数组的范围内增长和收缩。Aslice不存储任何数据,它只是描述数组的一部分。

去声明切片

var s []T

我们声明了一个T类型的切片。切片的声明就像一个数组,只是我们没有在方括号[]中指定任何大小。

$ go version
go version go1.18.1 linux/amd64

我们使用Go版本1.18。

去切片文字

可以使用切片文字创建切片。

package main

import "fmt"

func main() {
    var s1 = []int{2, 5, 6, 7, 8}

    s2 := []int{3, 5, 1, 2, 8}

    fmt.Println("s1:", s1)
    fmt.Println("s2:", s2)
}

在代码示例中,我们创建了两个切片。

var s1 = []int{2, 5, 6, 7, 8}

右边的表达式是一个切片字面量。

s2 := []int{3, 5, 1, 2, 8}

这里我们有一个速记等价物。

$ go run literal.go
s1: [2 5 6 7 8]
s2: [3 5 1 2 8]

Goslicemake函数

我们可以使用make内置函数在Go中创建新的切片。

func make([]T, len, cap) []T

make函数接受一个类型、一个长度和一个可选的容量。它分配一个大小等于给定容量的底层数组,并返回一个引用该数组的切片。

package main

import "fmt"

func main() {

    vals := make([]int, 5)

    fmt.Println("vals: ", vals)

    vals[0] = 1
    vals[1] = 2
    vals[2] = 3
    vals[3] = 4
    vals[4] = 5

    fmt.Println("vals: ", vals)
}

我们使用make函数创建一个大小为5的整数切片。最初,切片的元素全为零。然后我们为切片元素分配新值。

$ go run make_fun.go
vals:  [0 0 0 0 0]
vals:  [1 2 3 4 5]

Go切片长度和容量

len函数返回切片中的元素数。cap函数返回切片的容量。aslice的容量是底层数组中元素的数量,从切片中的第一个元素开始计数。

package main

import "fmt"

func main() {

    vals := make([]int, 5, 10)

    n := len(vals)
    c := cap(vals)

    fmt.Printf("The size is: %d\n", n)
    fmt.Printf("The capacity is: %d\n", c)

    vals2 := vals[0:4]
    n2 := len(vals2)
    c2 := cap(vals2)

    fmt.Printf("The size is: %d\n", n2)
    fmt.Printf("The capacity is: %d\n", c2)
}

在代码示例中,我们打印了两个切片的大小和容量。

$ go run len_cap.go
The size is: 6
The capacity is: 6
The size is: 4
The capacity is: 6

去切片数组或切片

我们可以通过对现有数组或切片进行切片来创建切片。

为了形成切片,我们指定了一个下限和一个上限:a[low:high]。这将选择一个半开范围,其中包括第一个元素,但不包括最后一个元素。

我们可以省略上限或下限以使用它们的默认值。下限默认为零,上限默认为切片长度。

package main

import "fmt"

func main() {

    vals := [...]int{1, 2, 3, 4, 5, 6, 7}

    s1 := vals[1:4]
    fmt.Printf("s1: %v, cap: %d\n", s1, cap(s1))

    s2 := vals[5:7]
    fmt.Printf("s2: %v, cap: %d\n", s2, cap(s2))

    s3 := vals[:4]
    fmt.Printf("s3: %v, cap: %d\n", s3, cap(s3))

    s4 := vals[2:]
    fmt.Printf("s4: %v, cap: %d\n", s4, cap(s4))

    s5 := vals[:]
    fmt.Printf("s5: %v, cap: %d\n", s5, cap(s5))
}

我们从整数数组创建切片。

vals := [...]int{1, 2, 3, 4, 5, 6, 7}

创建了一个整数数组。使用...运算符,Go会为我们计算数组的大小。

s2 := vals[5:7]
fmt.Printf("s2: %v, cap: %d\n", s2, cap(s2))

我们从vals数组创建一个切片。结果切片包含从索引5到索引7的元素;上限是非包容性的。

$ go run slicing.go
s1: [2 3 4], cap: 6
s2: [6 7], cap: 2
s3: [1 2 3 4], cap: 7
s4: [3 4 5 6 7], cap: 5
s5: [1 2 3 4 5 6 7], cap: 7

Go切片迭代

使用for循环,我们可以在Go中迭代切片元素。

package main

import "fmt"

func main() {

    words := []string{"falcon", "bold", "bear", "sky", "cloud", "ocean"}

    for idx, word := range words {

        fmt.Println(idx, word)
    }
}

在代码示例中,我们使用for/range语句遍历一段单词。

$ go run iteration.go
0 falcon
1 bold
2 bear
3 sky
4 cloud
5 ocean

在下面的示例中,我们使用经典的for循环迭代切片。

package main

import "fmt"

func main() {

    words := []string{"falcon", "bold", "bear", "sky", "cloud", "ocean"}

    for i := 0; i < len(words); i++ {

        fmt.Println(words[i])
    }
}

我们使用for语句遍历一段单词。

$ go run iteration2.go
falcon
bold
bear
sky
cloud
ocean

去切片追加

内置的append函数将新元素附加到切片。

func append(s []T, vs ...T) []T

第一个参数是T类型的切片,其余参数是要附加到切片的T值。

append的结果值是一个切片,其中包含原始切片的所有元素加上提供的值。如果后备数组太小而无法容纳所有给定值,则会分配一个更大的数组。返回的切片将指向新分配的数组。

package main

import "fmt"

func main() {

    vals := make([]int, 3)

    fmt.Printf("slice: %v; len: %d; cap: %d \n", vals, len(vals), cap(vals))

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

    vals = append(vals, 1)
    vals = append(vals, 2)
    vals = append(vals, 3)
    vals = append(vals, 4, 5, 6)

    fmt.Printf("slice: %v; len: %d; cap: %d \n", vals, len(vals), cap(vals))
}

在代码示例中,我们将新元素附加到一个已经有三个元素的切片。

vals := make([]int, 3)

首先,我们创建一个切片,其中三个元素初始化为0。

vals = append(vals, 1)
vals = append(vals, 2)
vals = append(vals, 3)
vals = append(vals, 4, 5, 6)

我们将六个值附加到切片。onego中可以追加多个元素。

$ go run appending.go
slice: [0 0 0]; len: 3; cap: 3
---------------------------
slice: [0 0 0 1 2 3 4 5 6]; len: 9; cap: 12

在幕后,Go扩大了底层数组以包含所有新元素。

package main

import (
    "fmt"
    "strings"
)

func main() {

    words := []string{}
    words = append(words, "an")
    words = append(words, "old")
    words = append(words, "falcon")

    res := strings.Join(words, " ")
    fmt.Println(res)
}

我们从一个空字符串切片开始。我们将三个词附加到切片中。然后我们使用strings.Join函数连接单词,同时在单词之间插入一个空格。

$ go run main.go
an old falcon

去切片复制

内置的copy函数复制一个切片。

func copy(dst, src []T) int

该函数返回复制的元素数。

package main

import "fmt"

func main() {

    vals := []int{1, 2, 3, 4, 5}

    vals2 := make([]int, len(vals))

    n := copy(vals2, vals)

    fmt.Printf("%d elements copied\n", n)

    fmt.Println("vals:", vals)
    fmt.Println("vals2:", vals2)
}

在代码示例中,我们复制了一段整数。

$ go run copying.go
5 elements copied
vals: [1 2 3 4 5]
vals2: [1 2 3 4 5]

去切片删除元素

没有从切片中删除项目的内置函数。我们可以使用append函数进行删除。

package main

import (
    "fmt"
)

func main() {

    words := []string{"falcon", "bold", "bear", "sky", "cloud", "ocean"}
    fmt.Println(words)

    words = append(words[1:2], words[2:]...)
    fmt.Println(words)

    words = append(words[:2], words[4:]...)
    fmt.Println(words)
}

在代码示例中,我们从切片中删除一个元素,然后删除两个元素。

words = append(words[1:2], words[2:]...)

这会从切片中移除第一个元素。我们通过附加两个切片并省略要删除的切片来完成删除。

$ go run remove_elements.go
[falcon bold bear sky cloud ocean]
[bold bear sky cloud ocean]
[bold bear ocean]

去切片独特的元素

在下一个示例中,我们生成一个包含唯一元素的切片。

package main

import "fmt"

func uniq(vals []int) []int {

    uvals := []int{}
    seen := make(map[int]bool)

    for _, val := range vals {

        if _, in := seen[val]; !in {

            seen[val] = true
            uvals = append(uvals, val)
        }
    }

    return uvals
}


func main() {

    vals := []int{1, 2, 2, 3, 4, 4, 5, 6, 7, 8, 8, 8, 9, 9}
    uvals := uniq(vals)

    fmt.Printf("Original slice: %v\n", vals)
    fmt.Printf("Unique slice: %v\n", uvals)
}

我们有一个包含重复元素的切片。我们创建了一个仅包含唯一元素的新切片。

seen := make(map[int]bool)

为了完成这项任务,我们创建了一个映射,为我们在切片中遇到的所有值存储一个布尔值true。

for _, val := range vals {

    if _, in := seen[val]; !in {

        seen[val] = true
        uvals = append(uvals, val)
    }
}

我们遍历切片中可能存在重复的元素。如果它不存在于seen映射中,我们将其存储在那里并将其附加到新的uvals切片。否则,我们将跳过if块。

$ go run uniq_elems.go
Original slice: [1 2 2 3 4 4 5 6 7 8 8 8 9 9]
Unique slice: [1 2 3 4 5 6 7 8 9]

去切片排序

Go包含用于对切片进行排序的sort包。

package main

import (
    "fmt"
    "sort"
)

func main() {

    words := []string{"falcon", "bold", "bear", "sky", "cloud", "ocean"}
    vals := []int{4, 2, 1, 5, 6, 8, 0, -3}

    sort.Strings(words)
    sort.Ints(vals)

    fmt.Println(words)
    fmt.Println(vals)
}

在代码示例中,我们对一片单词和整数进行排序。

$ go run sorting.go
[bear bold cloud falcon ocean sky]
[-3 0 1 2 4 5 6 8]

Go切片初值

切片的默认零值为nilnil切片的长度和容量为0,并且没有底层数组。

当我们使用make函数创建切片时,所有元素都被初始化为0。

package main

import "fmt"

func main() {

    var vals []int

    if vals == nil {
        fmt.Printf("slice is nil\n")
    }

    fmt.Printf("slice: %v; len: %d; cap: %d \n", vals, len(vals), cap(vals))

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

    var vals2 = make([]int, 5)
    fmt.Printf("slice: %v; len: %d; cap: %d \n", vals2, len(vals2), cap(vals2))
}

我们创建了两个具有默认零值和make-functioninitializedelements的切片。

$ go run initial.go
slice is nil
slice: []; len: 0; cap: 0
---------------------------
slice: [0 0 0 0 0]; len: 5; cap: 5

Goslice是引用类型

切片是Go中的引用类型。这意味着当我们将引用分配给新变量或将切片传递给函数时,将复制对切片的引用。

package main

import "fmt"

func main() {

    vals := []int{ 1, 2, 3, 4, 5, 6 }
    vals2 := vals

    vals2[0] = 11
    vals2[1] = 22

    fmt.Println(vals)
    fmt.Println(vals2)
}

在代码示例中,我们定义了一个切片并将切片分配给一个新变量。通过第二个变量所做的更改反映在原始切片中。

$ go run reftype.go
[11 22 3 4 5 6]
[11 22 3 4 5 6]

原始切片也被修改。

切片切片

Go切片还可以包含其他切片。

package main

import "fmt"

func main() {

    words := [][]string{
        {"sky", "ocean"},
        {"red", "blue"},
        {"C#", "Go"},
    }

    fmt.Printf("slice: %v; len: %d; cap: %d \n", words, len(words), cap(words))
}

该示例创建了一片切片。

$ go run sliceofslices.go
slice: [[sky ocean] [red blue] [C# Go]]; len: 3; cap: 3

过滤结构切片

在下一个例子中,我们过滤了一段Go结构。

package main

import "fmt"

type User struct {
    name       string
    occupation string
    country    string
}

func main() {

    users := []User{

        {"John Doe", "gardener", "USA"},
        {"Roger Roe", "driver", "UK"},
        {"Paul Smith", "programmer", "Canada"},
        {"Lucia Mala", "teacher", "Slovakia"},
        {"Patrick Connor", "shopkeeper", "USA"},
        {"Tim Welson", "programmer", "Canada"},
        {"Tomas Smutny", "programmer", "Slovakia"},
    }

    var programmers []User

    for _, user := range users {

        if isProgrammer(user) {
            programmers = append(programmers, user)
        }
    }

    fmt.Println("Programmers:")
    for _, u := range programmers {

        fmt.Println(u)
    }
}

func isProgrammer(user User) bool {

    return user.occupation == "programmer"
}

在代码示例中,我们定义了一部分用户。我们创建一个仅包含程序员的新切片。

type User struct {
    name       string
    occupation string
    country    string
}

User结构具有三个字段。

users := []User{

    {"John Doe", "gardener", "USA"},
    {"Roger Roe", "driver", "UK"},
    {"Paul Smith", "programmer", "Canada"},
    {"Lucia Mala", "teacher", "Slovakia"},
    {"Patrick Connor", "shopkeeper", "USA"},
    {"Tim Welson", "programmer", "Canada"},
    {"Tomas Smutny", "programmer", "Slovakia"},
}

这是User结构的原始切片。

var programmers []User

过滤后的用户/程序员存储在程序员切片中。

for _, user := range users {

    if isProgrammer(user) {
        programmers = append(programmers, user)
    }
}

我们遍历users切片,仅当用户满足isProgrammer谓词时,才将当前用户添加到programmers切片。

func isProgrammer(user User) bool {

    return user.occupation == "programmer"
}

对于occupation字段等于“程序员”的所有用户,IsProgrammer谓词返回true。

$ go run filter_slice_structs.go
Programmers:
{Paul Smith programmer Canada}
{Tim Welson programmer Canada}
{Tomas Smutny programmer Slovakia}

在本教程中,我们使用了Golang中的切片。

列出所有Go教程。

未经允许不得转载:我爱分享网 » 如何在Golang中使用切片

感觉很棒!可以赞赏支持我哟~

赞(0) 打赏