go语言基础之数组、切片 --青训营笔记

140 阅读5分钟

go语言的数组、切片

1、Array(数组)

1. 数组的定义
var 数组变量名 [元素数量] T
​
// 定义一个长度为5元素类型为int的数组a
var a [5]int

注意点:数组的长度必须是常量,并且长度是数组类型的一部分。一旦定义,长度不能变。

2. 数组的初始化 3种方式:
  1. 使用初始化列表来设置数组元素的值。
func main() {
        var testArray [3]int                        //数组会初始化为int类型的零值
    var numArray = [3]int{1, 2}                 //使用指定的初始值完成初始化
    var cityArray = [3]string{"北京", "上海", "深圳"} //使用指定的初始值完成初始化
}
  1. 可以让编译器根据初始值的个数自行推断数组的长度

    func main() {
        var testArray [3]int
        var numArray = [...]int{1, 2}
        var cityArray = [...]string{"北京", "上海", "深圳"}   
    }
    
  1. 以使用指定索引值的方式来初始化数组

    func main() {
        a := [...]int{1: 1, 3: 5}
        fmt.Println(a)                  // [0 1 0 5]
        fmt.Printf("type of a:%T\n", a) //type of a:[4]int
    }
    
3. 数组的遍历

遍历数组a有以下两种方法:

func main() {
    var a = [...]string{"北京", "上海", "深圳"}
    // 方法1:for循环遍历
    for i := 0; i < len(a); i++ {
        fmt.Println(a[i])
    }
​
    // 方法2:for range遍历
    for index, value := range a {
        fmt.Println(index, value)
    }
}
4. 多维数组的定义和遍历方式
//二维数组的定义
func main() {
    a := [3][2]string{
        {"北京", "上海"},
        {"广州", "深圳"},
        {"成都", "重庆"},
    }
    fmt.Println(a) //[[北京 上海] [广州 深圳] [成都 重庆]]
    fmt.Println(a[2][1]) //支持索引取值:重庆
}
​
//二维数组的遍历
func main() {
    a := [3][2]string{
        {"北京", "上海"},
        {"广州", "深圳"},
        {"成都", "重庆"},
    }
    for _, v1 := range a {
        for _, v2 := range v1 { //注意这里
            fmt.Printf("%s\t", v2)
        }
        fmt.Println()
    }
}

2、 切片(slice)

1. 切片的定义:

切片(Slice)是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封装。它非常灵活,支持自动扩容。

为什么要切片:(因为数组是在定义的时候就固定了长度,当超过数组长度就没办法添加,因此引入了切片,可以动态扩容,很类似c++的vector)。、

声明切片类型的基本语法如下:

var name [ ] T
​
func main() {
    // 声明切片类型
    var a [ ]string              //声明一个字符串切片
    var b = [ ]int{ }             //声明一个整型切片并初始化
    var c = [ ]bool{false, true} //声明一个布尔切片并初始化
    var d = [ ]bool{false, true} //声明一个布尔切片并初始化
    
}
2. 切片的长度和容量

切片拥有自己的长度和容量,我们可以通过使用内置的len()函数求长度,使用内置的cap()函数求切片的容量。

3.简单切片表达式

切片的底层就是一个数组,所以我们可以基于数组通过切片表达式得到切片。 切片表达式中的lowhigh表示一个索引范围(左包含,右不包含),也就是下面代码中从数组a中选出1<=索引值<4的元素组成切片s,得到的切片长度=high-low,容量等于得到的切片的底层数组的容量。

func main() {
    a := [5]int{1, 2, 3, 4, 5}
    s := a[1:3]  // s := a[low:high]
    fmt.Printf("s:%v len(s):%v cap(s):%v\n", s, len(s), cap(s))
}
 //s:[2 3] len(s):2 cap(s):4

为了方便起见,可以省略切片表达式中的任何索引。省略了low则默认为0;省略了high则默认为切片操作数的长度:

a[2:]  // 等同于 a[2:len(a)]
a[:3]  // 等同于 a[0:3]
a[:]   // 等同于 a[0:len(a)]

]

4. 使用make()函数构造切片

我们上面都是基于数组来创建的切片,如果需要动态的创建一个切片,我们就需要使用内置的make()函数,格式如下:

make([ ]T, size, cap)

其中:

  • T:切片的元素类型
  • size:切片中元素的数量
  • cap:切片的容量

举个例子:

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

上面代码中a的内部存储空间已经分配了10个,但实际上只用了2个。 容量并不会影响当前元素的个数,所以len(a)返回2,cap(a)则返回该切片的容量。

5. 切片的本质

切片的本质就是对底层数组的封装,它包含了三个信息:底层数组的指针、切片的长度(len)和切片的容量(cap)。

6. 切片遍历

切片的遍历方式和数组是一致的,支持索引遍历和for range遍历。

func main() {
    s := []int{1, 3, 5}
​
    for i := 0; i < len(s); i++ {
        fmt.Println(i, s[i])
    }
    
    for index, value := range s {
        fmt.Println(index, value)
    }
}
7. append()方法为切片添加元素

Go语言的内建函数append()可以为切片动态添加元素。 可以一次添加一个元素,可以添加多个元素,也可以添加另一个切片中的元素(后面加…)。

func main(){
    var s []int
    s = append(s, 1)        // [1]
    s = append(s, 2, 3, 4)  // [1 2 3 4]
    s2 := [ ]int{5, 6, 7}  
    s = append(s, s2...)    // [1 2 3 4 5 6 7]
}

注意: 通过var声明的零值切片可以在append()函数直接使用,无需初始化。

var s []int
s = append(s, 1, 2, 3)

每个切片会指向一个底层数组,这个数组的容量够用就添加新增元素。当底层数组不能容纳新增的元素时,切片就会自动按照一定的策略进行“扩容”,此时该切片指向的底层数组就会更换。“扩容”操作往往发生在append()函数调用时,所以我们通常都需要用原变量接收append函数的返回值。

8. 从切片中删除元素

Go语言中并没有删除切片元素的专用方法,我们可以使用切片本身的特性来删除元素。 代码如下:

func main() {
    // 从切片中删除元素
    a := []int{30, 31, 32, 33, 34, 35, 36, 37}
    // 要删除索引为2的元素
    a = append(a[:2], a[3:]...)
    fmt.Println(a) //[30 31 33 34 35 36 37]
}

总结一下就是:要从切片a中删除索引为index的元素,操作方法是a = append(a[:index], a[index+1:]...)

总结:go中的数组其实就和其他语言的数组类似,而切片其实就类似于c++中的vector,可以动态扩容。