Go-扩展语法(数组、切片、集合)

一、数组(array)

1、定义数组
package main

import "fmt"

func main() {
    // 定义一个拥有5个int元素的数组
    var arr1 [5]int
    // 初始化一个拥有3个int元素的数组,注意初始化数组则必须给初始值
    arr2 := [3]int{1, 4, 9}
    // 初始化一个有多个元素的数组,但不指定具体数目,让Go自己去数
    arr3 := [...]int{1, 2, 4, 5, 7, 8, 9}
    // 定义一个二维数组
    var arr4 [4][5]int

    // 打印
    fmt.Println(arr1) // [0 0 0 0 0]
    fmt.Println(arr2) // [1 4 9]
    fmt.Println(arr3) // [1 2 4 5 7 8 9]
    fmt.Println(arr4) // [[0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0]]

}

 

2、遍历数组
(1)单纯使用for循环遍历数组【不常用】
package main

import "fmt"

func main() {
    // 定义一个数组,没有声明个数,让Go自己去数
    arr := [...]int{1, 2, 4, 5, 7, 8, 9}
    // 遍历数组
    for i := 0; i < len(arr); i++ {
        fmt.Println(arr[i]) // 1, 2, 4, 5, 7, 8, 9
    }
}

 

(2)使用for循环配合range关键字遍历数组

这里使用range关键字先获取数组的元素下标,再根据元素下标输出元素值

package main

import "fmt"

func main() {
    // 定义一个数组,没有声明个数,让Go自己去数
    arr := [...]int{1, 2, 4, 5, 7, 8, 9}
    //
    for i := range arr {
        fmt.Println(arr[i]) // 1, 2, 4, 5, 7, 8, 9
    }
}

 

(3)使用for循环配合range关键字,直接输出元素值

这里使用range关键字时不接收元素下标,只接收元素值

package main

import "fmt"

func main() {
    // 定义一个数组,没有声明个数,让Go自己去数
    arr := [...]int{1, 2, 4, 5, 7, 8, 9}
    // 循环遍历数组,不接收range函数返回的数组元素下标,只接收数组元素的值
    for _, v := range arr {
        fmt.Println(v) // 1, 2, 4, 5, 7, 8, 9
    }
}

在Go语言中,数组是值类型,调用func f(arr [10]int) 会拷贝数组,而不是引用数组,Go语言中,也没有引用这个概念。

虽然可以使用指针实现引用传递的效果,但是用起来很麻烦,那Go语言中如何实现和其他语言类似的数组引用传递呢。

其实在Go语言中,一般不会直接使用数组,而是使用切片,下面就会对切片进行学习。

 

二、切片(Slice)

切片在Go语言中是一个非常重要的知识点。

1、切片的基本应用
func main() {
    arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8}

    // 初始化一个切片
    s := arr[2:6] 
    fmt.Println(s) // [2 3 4 5]

    // 将切片继续切
    s = s[1:]
    fmt.Println(s) // [3 4 5]

    // 将切片s2继续切
    s = s[1:]
    fmt.Println(s) // [4 5]

}
2、切片的扩展

Go语言中的切片有一个扩展的概念,扩展是基于它的原始数组向后扩展的。

想要了解扩展之前,需要理解两个概念,长度和容量。长度用len函数获取,容量用cap函数获取。

长度就是表示数组或切片的元素个数;容量则表示数组或切片可以直接操作的元素加上可扩展元素的总个数。在数组中,容量和长度相同;但在切片中,容量往往大于长度。而且要注意,切片只能向后扩展,不能向前扩展。

也就是说,一个数组arr有9个元素[0, 1, 2, 3, 4, 5, 6, 7, 8],切片s1是基于数组arr取下标3到下标5中间的元素,此时切片s1里的元素是[3,4],此时取s1[0,2],会得到结果[3, 4, 5],5这个元素切片s1里面其实是没有的,它是从切片的原始数组arr中取得的,这就是切片的扩展。

但你从切片s1中取值,你不可能去s1[-1:2],因此切片只能向后扩展,是不能向前扩展的。

举例:

func main() {
    arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8}

    // 初始化一个切片
    s1 := arr[3:5]
    fmt.Println(s1) // [3 4]

    fmt.Println(len(arr)) // 9 [0, 1, 2, 3, 4, 5, 6, 7, 8]
    fmt.Println(cap(arr)) // 9 [0, 1, 2, 3, 4, 5, 6, 7, 8]

    fmt.Println(len(s1)) // 2 [3 4]
    fmt.Println(cap(s1)) // 6 [3, 4, 5, 6, 7, 8]

    fmt.Println(s1[4:6]) // [7 8]
    fmt.Println(s1[4:7]) // slice bounds out of range [:7] with capacity 6

}

小提示:不断修改代码去验证自己的猜想,这样才能更深刻的理解Go语言中的切片扩展这个概念。

 

三、集合(Map)

1、定义空map
通过make方式:
func main() {
    map2 := make(map[string]int)
    fmt.Println(map2) // map[]
}
通过var方式:
func main() {
    var map3 map[string]int
    fmt.Println(map3) // map[]
}
2、简单定义一个有元素值的map
func main() {
    // 初始化一个map
    map1 := map[string]string {
        "name":"haveyb",
        "sex":"man",
        "site":"https://www.haveyb.com",
    }
    fmt.Println(map1) // map[name:haveyb sex:man site:https://www.haveyb.com]
}
3、遍历map
func main() {
    // 初始化一个map
    map1 := map[string]string {
        "name":"haveYb",
        "sex":"man",
        "site":"https://www.haveyb.com",
    }
    // 遍历map1
    for k,v := range map1 {
        fmt.Println(k, v)
    }
}

这里值得注意的是,map中的元素是无序的,也就是说,遍历得到的结果集虽然相同,但是每次遍历得到的结果,顺序可能不一样。

4、获取map中的某个元素
func main() {
    // 初始化一个map
    map1 := map[string]string {
        "name":"haveYb",
        "sex":"man",
        "site":"https://www.haveyb.com",
    }
    // 获取map中的某个元素的值
    userName := map1["name"]
    fmt.Println(userName) // haveYb
}

值得注意的是,Go语言中,即使我们拼写错误,找一个map中不存在的key,Go也不会报错,而是返回给我们一个zero value,我们定义的是string,就会返回给我们一个空字符串。

针对即使没有元素值,Go也不报错的问题,我们通常这么处理:

func main() {
    // 初始化一个map
    map1 := map[string]string {
        "name":"haveYb",
        "sex":"man",
        "site":"https://www.haveyb.com",
    }

    // 查找一个不存在的元素,会得到结果"map中不存在该元素"
    if userName,ok := map1["name2"]; ok {
        fmt.Println(userName)
    } else {
        fmt.Println("map中不存在该元素")
    }
}
5、删除map中的某个元素
func main() {
    // 初始化一个map
    map1 := map[string]string {
        "name":"haveYb",
        "sex":"man",
        "site":"https://www.haveyb.com",
    }
    // 删除map中的元素
    delete(map1, "site")
    fmt.Println(map1) // map[name:haveYb sex:man]
}

值得注意的是,Go语言中,即使我们删除的是map中不存在的元素,Go语言也不会不错,这一点和Redis很像。

6、map的key

除了slice、map、function,其他内建类型都可以作为map的key

自定义类型struct如果不包含slice、map、function,也可以作为map的key