前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go语言学习(四)| 数组、切片、集合

Go语言学习(四)| 数组、切片、集合

作者头像
Mervyn
发布2020-07-21 14:53:34
2900
发布2020-07-21 14:53:34
举报

array

声明数组

array由 [n]<type> 定义,n为array的长度,<type>标示希望存储的内容的类型。例:

代码语言:javascript
复制
var arr [10]int     //声明一个int类型的数组
arr[0] = 42         //数组下标是从0开始的
arr[1] = 13         //赋值操作

数组的索引从 0 开始到 length - 1 结束。数组中的所有元素都被自动赋值为数组类型的零值。

NOTE 数组的大小是类型的一部分.

由于长度也是数组类型的一部分,因此 [3]int 与 [4]int 是不同的类型,数组也就不能改变长度。

Go 中的数组是值类型而不是引用类型。

数组之间的赋值是值的赋值,即当把一个数组作为参数传入函数的时候,传入的其实是该数组的副本,而不是它的指针。如果要使用指针,那么就需要用到后面介绍的 slice 类型了。

初始化数组

代码语言:javascript
复制
a := [3]int{1, 2, 3}

初始化数组中 {} 中的元素个数不能大于 [] 中的数字。如果忽略 [] 中的数字不设置数组大小,Go 语言会根据元素的个数来设置数组的大小:

代码语言:javascript
复制
a := [...]int{1, 2, 3}

初始化数组时,可以只初始化部分数组的值,例:

代码语言:javascript
复制
b := [10]int{1, 2, 3} //声明了一个长度为10的int数组,其中前3个元素初始化为1、2、3,其他默认为0。

二维数组

代码语言:javascript
复制
package main

import "fmt"

func main() {
    a := [2][2]int{ [2]int{1, 2}, [2]int{3, 4} }
    fmt.Println(a)

    b := [2][3] int { {1, 2, 3}, {2, 2, 3}}
    fmt.Println(b)  //[[1 2 3] [2 2 3]]

    c := [2][2]int{[...]int{1, 2}, [...]int{3, 4} }
    fmt.Println(c)
}

slice

slice 与 array 接近,但是在新的元素加入的时候可以增加长度.slice 是一个指向 array 的指针,这是其与 array 不同的地方;slice 是引用类型,这意味着当赋值某个 slice 到另外一个变量,两个引用会指向同一个 array.

创建切片

基于数组创建

例:

代码语言:javascript
复制
package main

import "fmt"

func main() {
    //定义一个 5 个元素的 array,序号从 0 到 4
    a := [...]int{1, 2, 3, 4, 5}
    fmt.Println("array a is:", a)

    //从序号 2 至 3 创建 slice,它包含元素 3, 4 , s1 := a[0:6]; 编译时会报错。因为超出了数组范围
    s1 := a[2:4]
    fmt.Println("slice s1 is:", s1)

    //从序号 1 至 4 创建,它包含元素 2, 3, 4, 5
    s2 := a[1:5]
    fmt.Println("slice s2 is:", s2)

    //用 array 中的所有元素创建 slice,这是 a[0:len(a)] 的简化写法
    s3 := a[:]
    fmt.Println("slice s3 is:", s3)

    //从序号 0 至 3 创建,这是 a[0:4] 的简化写法,得到 1, 2, 3, 4
    s4 := a[:4]
    fmt.Println("slice s4 is:", s4)

    //从 slice s2 创建 slice,注意 s5 仍然指向 array a。a的值变了,slice的值也随之改变
    s5 := s2[:]
    fmt.Println("slice s5 is:", s5)

    fmt.Println("-----------------")
    s2[0] = 1
    fmt.Println("array a is:", a)
    fmt.Println("slice s1 is:", s1)
    fmt.Println("slice s2 is:", s2)
    fmt.Println("slice s3 is:", s3)
    fmt.Println("slice s4 is:", s4)
    fmt.Println("slice s5 is:", s5)

}

上述执行输出结果为:

代码语言:javascript
复制
array a is: [1 2 3 4 5]
slice s1 is: [3 4]
slice s2 is: [2 3 4 5]
slice s3 is: [1 2 3 4 5]
slice s4 is: [1 2 3 4]
slice s5 is: [2 3 4 5]
-----------------
array a is: [1 1 3 4 5]
slice s1 is: [3 4]
slice s2 is: [1 3 4 5]
slice s3 is: [1 1 3 4 5]
slice s4 is: [1 1 3 4]
slice s5 is: [1 3 4 5]
直接创建
  • 创建一个初始元素个数为5的数组切片,元素初始值为0:
代码语言:javascript
复制
mySlice1 := make([]int, 5)
  • 创建一个初始元素个数为5的数组切片,元素初始值为0,并预留10个元素的存储空间:
代码语言:javascript
复制
mySlice2 := make([]int, 5, 10)
  • 直接创建并初始化包含5个元素的数组切片:
代码语言:javascript
复制
mySlice3 := []int{1, 2, 3, 4, 5}

slice 和 array 在声明时的区别

  • 声明数组时,方括号内写明了数组的长度或使用 ... 自动计算长度
  • 声明 slice 时,方括号内没有任何字符。
  • slice 可以从一个数组或一个已经存在的 slice 中再次声明。slice 通过array[i:j]来获取,其中 i 是数组的开始位置,j 是结束位置,但不包含 array[j] ,它的长度是 j - i .
代码语言:javascript
复制
// 声明一个含有10个元素元素类型为byte的数组
var ar = [10]byte {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}

// 声明两个含有byte的slice
var a, b []byte

// a指向数组的第3个元素开始,并到第五个元素结束,
a = ar[2:5]
//现在a含有的元素: ar[2]、ar[3]和ar[4]

// b是数组ar的另一个slice
b = ar[3:5]
// b的元素是:ar[3]和ar[4]

slice的一些简便操作

  • slice 的默认开始位置是 0,ar[:n] 等价于 ar[0:n]
  • slice 的第二个序列默认是数组的长度,ar[n:] 等价于 ar[n:len(ar)]
  • 如果从一个数组里面直接获取 slice,可以这样 ar[:],因为默认第一个序列是 0,第二个是数组的长度,即等价于 ar[0:len(ar)]

操作 slice 几个有用的内置函数

  • len 获取 slice 的长度。
  • cap 获取slice的最大容量。
  • append 向 slice 里面追加一个或者多个元素,然后返回一个和 slice 一样类型的 slice。
  • copy 函数 copy 从源 slice 的 src 中复制元素到目标 dst,并且返回复制的元素的个数。

函数 copy 从源 slice src 复制元素到目标 dst,并且返回复制的元素的个数。源和目标可能重叠。复制的数量是 len(src) 和 len(dst) 中的最小值。

append 函数会改变 slice 所引用的数组的内容,从而影响到引用同一数组的其它 slice。 但当 slice 中没有剩余空间(即(cap - len) == 0)时,此时将动态分配新的数组空间。返回的 slice 数组指针将指向这个空间,而原数组的内容将保持不变;其它引用此数组的 slice 则不受影响。

例:

代码语言:javascript
复制
package main
import "fmt"
func main(){
    arr := [10]int{1, 2, 3, 4, 5}
    s1 := arr[0:2]
    fmt.Println(len(s1))    //输出2
    fmt.Println(cap(s1))    //输出10
}

map

声明 map

一般定义 map 的方法是:

代码语言:javascript
复制
map[<from type>] <to type>

例:

代码语言:javascript
复制
var numbers map[string] int

numbers := make(map[string] int)

当只需要声明一个 map 的时候,使用 make 的形式:monthdays := make(map[string]int)例:

代码语言:javascript
复制
package main
import "fmt"
func main(){
    monthdays := map[string]int{
        "Jan": 31, "Feb": 28, "Mar": 31,
        "Apr": 30, "May": 31, "Jun": 30,
        "Jul": 31, "Aug": 31, "Sep": 30,
        "Oct": 31, "Nov": 30, "Dec": 31,//此处的逗号是必须的
    }

    for key, val := range monthdays {
        fmt.Printf("key = %s, val = %d\n", key, val)
    }
}

当在 map 中索引(搜索)时,使用方括号。例如打印出 12 月的天数:fmt.Printf("%d\n", monthdays["Dec"])这个map就像我们平常看到的表格一样,左边列是 key ,右边列是值

使用map过程中需要注意的几点:

  • map 是无序的,所以上述例子每次打印出来的结果顺序都不一样都会不一样,它不能通过 index 获取,而必须通过 key 获取
  • map 的长度是不固定的,也就是和 slice 一样,也是一种引用类型
  • 内置的 len 函数同样适用于 map,返回 map 拥有的 key 的数量
  • map 的值可以很方便的修改,通过 monthdays["Feb"] = 20 可以很容易的把 key 为 Feb 的字典值改为 20
  • map 和其他基本类别不同,它不是 Thread-safe ,在多个 goroutine 存取时,必须使用 mutex lock 机制。 Go1.9 以后可用 sync.Map 解决这个问题
  • map 的初始化可以通过 key:val 的方式初始化值,同时 map 内置有判断是否存在 key 的方式

通过 delete 删除 map 的元素

例:

代码语言:javascript
复制
package main

func main() {
    monthdays := map[string]int{
        "Jan": 31, "Feb": 28, "Mar": 31,
        "Apr": 30, "May": 31, "Jun": 30,
        "Jul": 31, "Aug": 31, "Sep": 30,
        "Oct": 31, "Nov": 30, "Dec": 31,
    }

    //删除map中Feb元素
    delete(monthdays, "Feb")

    //map 有两个返回值,第一个返回值为该 key 的值;
    // 第二个返回值,如果不存在 key,那么 ok 为 false,如果存在 ok 为 true
    val, ok := monthdays["Feb"]

    //判断monthdays["Feb"]是否存在
    if ok {
        println("Feb is in the map and its value is", val)
    } else {
        println("Feb isn't in the map")
    }
}

输出结果:Feb isn't in the map

例2:

代码语言:javascript
复制
package main

import "fmt"

type Vertex struct {
    Lat, Long float64
}

var ms = map[string]Vertex{
    "Bell Labs": {40.68433, -74.39967},
    "Google":    {37.42202, -122.08408},
}

func main() {
    fmt.Println(ms)
}

map 也是一种引用类型,如果两个 map 同时指向一个底层,那么一个改变,另一个也相应的改变:

代码语言:javascript
复制
package main

import "fmt"

func main() {
    m := make(map[string]string)
    fmt.Println("map m is: ", m)

    m["Hello"] = "Bonjour"
    m["World"] = "XXXXX"
    fmt.Println("map m is: ", m)

    m1 := m
    fmt.Println("map m1 is: ", m1)

    m1["Hello"] = "Salut"  // 现在m["hello"]的值已经是Salut了
    fmt.Println("map m is: ", m)
    fmt.Println("map m1 is: ", m1)
}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-12-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 开发技术那些事 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • array
    • 声明数组
      • 初始化数组
        • 二维数组
        • slice
          • 创建切片
            • 基于数组创建
            • 直接创建
          • slice 和 array 在声明时的区别
            • slice的一些简便操作
              • 操作 slice 几个有用的内置函数
              • map
                • 声明 map
                  • 通过 delete 删除 map 的元素
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档