1. 前言

go中的数组不同于C、php,没有那么灵活,但是拥有切片的类型。一般开发上,常用切片,下面我们就来探索下它们的奥妙。

2. 数组

go数组是同一种数据类型的固定长度的数据结构,其数组长度也是数组类型的一部分。

声明格式:

var identifier [len]type

例如:

var arr [8]int
var brr [8]string

如上 arr 的长度是 5,类型是int,索引范围从 0 到 7 【len(arr)-1】

数组是可变的。对索引项为 i 的数组元素赋值可以这么操作:arr[i] = value,

如果索引超出数组最大范围,会触发访问越界报错

内置函数 len 和 cap 都可返回数组长度 (元素数量)。

runtime error: index out of range

2.1. 数组初始化

  • 未初始化元素值为 0
var a = [5]int{1, 2}

a := [5]int{1, 2}
  • 通过...可忽略数组长度(其数组长度由值确定),相当于切片。
b := [...]int{1, 2, 3}
  • 使用索引号初始化元素。
c := [5]int{1: 80, 4: 50}
  • 使用索引号赋值。
var d [5]int

d[3] = 10
  • 多维数组
var dr1 [2][3]int
var dr2 = [...][3]int{ {1, 2, 3}, {6, 7, 8} } // 第二维度不能用 "..."

3. 切片

切片的长度是不固定的,是对数组一个连续片段的引用,是一个长度可变的数组。

声明切片的格式是:

var identifier []type(不需要说明长度)

从声明中可看出切片和数组明显区别在([]里不需要len),切片不需要指定长度,这样切片就不会使用额外的内存, 效率会比数组大,所以在go项目开发中切片比数组更常用。

3.1. 切片初始化

切片的初始化格式是:

var slice []type = arr[start:end]

  • slice在未初始化之前默认为 nil,长度为 0。

  • slice 是由数组 arr 从 start 索引到 end-1 索引之间的元素构成的子集,(slice1[0] = arr[start])

  • 若 var slice []type = arr[:],slice 就等于完整的 arr 数组,是 arr[0:len(arr)] 的一种缩写,还可直接 slice = &arr

  • cap可测量出切片的容量,它等于切片从第一个元素开始,到相关数组末尾的元素个数。

  • 切片的长度不会超过它的容量,0 <= len(slice) <= cap(slice) 永远成立。

如:

package main

import (
    "fmt"
)

func main() {
    var arr = [5]int{0, 1, 2, 3, 4}

    a := arr[:]           // arr[0:len(arr)]的简化写法
    b := arr[:1]          // arr[0:1]的简化写法
    c := arr[:len(arr)-1] //去掉切片的最后一个元素

    fmt.Print(a, b, c)
}

输出:[0 1 2 3 4] [0] [0 1 2 3]

3.2. 用make来创建切片

当相关数组还没有定义时,我们可以使用 make() 函数来创建一个切片,同时创建好相关数组:var slice []type = make([]type, len)

  • 可简化成 slice := make([]type, len)
package main
import "fmt"

func main() {
    slice := make([]int, 10)
    for i := 0; i < len(slice); i++ {
        slice[i] = 2 * i
    }

    for i := 0; i < len(slice); i++ {
        fmt.Printf(" slice[%d] = %d\n", i, slice[i])
    }
    fmt.Printf("len is %d\n", len(slice))
    fmt.Printf("cap is %d\n", cap(slice))
}

输出:

 slice[0] = 0
 slice[1] = 2
 slice[2] = 4
 slice[3] = 6
 slice[4] = 8
 slice[5] = 10
 slice[6] = 12
 slice[7] = 14
 slice[8] = 16
 slice[9] = 18
len is 10
cap is 10

3.3. append追加切片元素

func append(slice []Type, elems ...Type) []Type

向 slice 尾部添加数据,返回新的 slice 对象。

package main
import "fmt"

func main() {
    a := []int{1, 2}
    b := []int{3, 4}
    c := append(a, b...)
    d := append(c, 5)
    e := append(d, 6, 7)

    fmt.Printf("slice a : %v\n", a)
    fmt.Printf("slice b : %v\n", b)
    fmt.Printf("slice c : %v\n", c)
    fmt.Printf("slice d : %v\n", d)
    fmt.Printf("slice e : %v\n", e)
}

输出:

slice a : [1 2]
slice b : [3 4]
slice c : [1 2 3 4]
slice d : [1 2 3 4 5]
slice e : [1 2 3 4 5 6 7]

3.4. 切片拷贝

Go语言的内置函数copy()可以将一个数组切片复制到另一个数组切片

copy(dst, src []Type) int

copy函数的第一个参数是要复制的目标slice,第二个参数是源slice,函数会返回成功复制的元素的个数。

如果两个切片不一样大,就会以长度小的切片元素个数进行复制。两个 slice 可指向同一底层数组,允许元素区间重叠。

package main

import (
    "fmt"
)

func main() {
    a := []int{1, 2, 3}
    fmt.Printf("slice a : %v\n", a)
    b := make([]int, 5)
    fmt.Printf("slice b : %v\n", b)
    copy(b, a)
    fmt.Printf("copied slice a : %v\n", a)
    fmt.Printf("copied slice b : %v\n", b)
    c := []int{4, 5}
    fmt.Printf("slice c : %v\n", c)
    copy(c, b)
    fmt.Printf("copied slice c : %v\n", c)
    c = append(c, 6, 7, 8)
    fmt.Printf("last slice c : %v\n", c)
}

输出结果:

slice a : [1 2 3]
slice b : [0 0 0 0 0]
copied slice a : [1 2 3]
copied slice b : [1 2 3 0 0]
slice c : [4 5]
copied slice c : [1 2]
last slice c : [1 2 6 7 8]

3.5. 字符串和切片

string可看作是一个byte的数组,可以进行切片操作。

package main

import (
    "fmt"
)

func main() {
    str := "hello world"
    a := str[0:5]
    b := str[6:]

    fmt.Println(a)
    fmt.Println(b)
}

输出:

hello
world

字符串是不可变的,它不能像数组切片那样可以直接通过索引赋值去改变,需要操作可转化,如下:

package main

import (
    "fmt"
)

func main() {
    a := "hello world"
    s := []byte(a) // 含有中文字符需要用[]rune(a)
    s[0] = 'H'
    s[6] = 'W'
    s = append(s, '!')
    a = string(s)
    fmt.Println(a)

    // 含有中文字符
    b := "我是中国人 I'm proud"
    z := []rune(b)
    z[5] = '!'
    z = z[:6]
    b = string(z)

    fmt.Println(b)
}

输出:

Hello World!
我是中国人!

3.6. slice遍历

package main

import (
    "fmt"
)

func main() {
    data := []int{1, 2, 3, 4, 5}
    for index, value := range data {
        fmt.Printf("inde : %v , value : %v\n", index, value)
    }
}

输出:

inde : 0 , value : 1
inde : 1 , value : 2
inde : 2 , value : 3
inde : 3 , value : 4
inde : 4 , value : 5
Copyright © yzx该文章修订时间: 2021-10-11 20:08:59

results matching ""

    No results matching ""