Go语言自学十八式:数组和切片篇

数组

数组是一个由固定长度的特定类型元素组成的序列,因为长度固定,所以在Go语言中很少直接使用数组。

声明数组,并给该数组里的每个元素赋值:

// [3] 里的3 表示该数组的元素个数 
var arr [3]int
arr[0] = 1
arr[1] = 2
arr[2] = 3

声明并直接初始化数组:

// 第一种方法
var arr [3]int = [3]int{1,2,3}

// 第二种方法
arr := [3]int{1,2,3}

[ ]中的3 表示数组中元素的个数,如此声明为硬编码(一旦声明无法修改)。如此可以使用[...]来根据实际情况来分配空间:

import (
    "fmt"
)

func main() {
    arr01 := [...]int{1, 2, 3}
    arr02 := [...]int{1, 2, 3, 4}
    fmt.Printf("%d 的类型是: %T\n", arr01, arr01)
    fmt.Printf("%d 的类型是: %T\n", arr02, arr02)
    fmt.Printf(arr01 == arr02)
}

输出如下:
[1 2 3] 的类型是: [3]int
[1 2 3 4] 的类型是: [4]int
false

说明 [3]int 和 [4]int 是不同的类型。

使用 type 关键字可以定义一个类型字面量,后面只要想定义一个容器大小为3,元素类型为int的数组,都可以使用这个别名类型:

import (
    "fmt"
)

func main() {
    type arr3 [3]int

    myarr := arr3{1,2,3}
    fmt.Printf("%d 的类型是: %T", myarr, myarr)
}

输出如下:
[1 2 3] 的类型是: main.arr3

切片

切片(Slice)与数组一样,也是可以容纳若干类型相同的元素的容器。

与数组不同的是,无法通过切片类型来确定其长度。每个切片都会将数组作为其底层数据结构。我们也把这样的数组称为切片的底层数组。

切片是对数组的一个连续片段的引用,所以切片是一个引用类型,这个片段可以是整个数组,也可以是由起始和终止索引标识的一些项的子集,需要注意的是,终止索引标识的项不包括在切片内(意思是这是个左闭右开的区间):

import (
    "fmt"
)

func main() {
    myarr := [...]int{1, 2, 3}
    fmt.Printf("%d 的类型是: %T", myarr[0:2], myarr[0:2])
}

输出 如下
[1 2] 的类型是: []int

很显然,从切片类型无法知道该切片的长度。

切片构造方式

1. 对数组进行片段截取(比如,myarr[0:2],区间左半右开)

2. 从头声明赋值:

// 声明字符串切片
var strList []string

// 声明整型切片
var numList []int

// 声明一个空切片
var numListEmpty = []int{}

和数组的区别是,数组声明必需指定数组长度。

3. 使用 make 函数构造,make 函数的格式:

//切片的三个属性:类型(Type),长度(size),容量(capcity)
make([]Type, size, capcity)

举个栗子:

import (
   "fmt"
)

func main() {
   a := make([]int, 2)
   b := make([]int, 2, 10)
   fmt.Println(a, b)
   fmt.Println(len(a), len(b))
   fmt.Println(cap(a), cap(b))
}

输出 如下
[0 0] [0 0]
2 2
2 10

对于 len( ) 和 cap( ),

  • len( ) 代表这个切片当前个元素,所以cap >= len

  • cap( ) 代表切片最多可以容纳多少元素

由于 切片是引用类型,所以不对它进行赋值的话,它的默认值(零值)是 nil:

var myarr []int
fmt.Println(myarr == nil)
// true

切片本身是引用类型,它更像是 Python 中的 list ,我们可以对它 使用append 进行元素的添加:

import (
    "fmt"
)

func main() {
    myarr := []int{1}
    // 追加一个元素
    myarr = append(myarr, 2)
    // 追加多个元素
    myarr = append(myarr, 3, 4)
    // 追加一个切片, ... 表示解包,不能省略
    myarr = append(myarr, []int{7, 8}...)
    // 在第一个位置插入元素
    myarr = append([]int{0}, myarr...)
    // 在中间插入一个切片(两个元素)
    myarr = append(myarr[:5], append([]int{5,6}, myarr[5:]...)...)
    fmt.Println(myarr)
}

输出 如下
[0 1 2 3 4 5 6 7 8]

思考一下

import (
    "fmt"
)

func main() {
    var numbers4 = [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    myslice := numbers4[4:6:8]
    fmt.Printf("myslice为 %d, 其长度为: %d\n", myslice, len(myslice))

    myslice = myslice[:cap(myslice)]
    fmt.Printf("myslice的第四个元素为: %d", myslice[3])
}

输出如下:
myslice为 [5 6], 其长度为: 2
myslice的第四个元素为: 8

为什么一开始 myslice 的长度为2,却能访问到第四个元素?

首先,numbers4[4:6:8]中的 最后一个参数为容量上界索引,即切片能访问的数组最大索引(不包括)

所以,myslice[:cap(myslice)] 中cap(myslice)返回4,所以 myslice[:8]即 [ 5, 6, 7, 8],新的myslice长度变为4。

所以可以访问到第四个元素。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薛定谔的猫96

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值