美文网首页
Go语言数组、切片、映射

Go语言数组、切片、映射

作者: LightiSnow | 来源:发表于2020-02-05 15:47 被阅读0次

数组

  • 声明和初始化
var array [5]int
var array [5]int{1, 2, 3, 4, 5}
array := [...]int{1, 2, 3, 4, 5}
array := [5]int{1: 20, 2:20}
  • 访问指针数组的元素
// 用整型指针初始化索引为0和1的数组元素
array := [5]*int{0: new(int), 1: new(int)}

// 为索引为0和1的元素赋值
*array[0]=10
*array[1]=20

相同类型(数组长度和每个数组元素类型相同)的数组变量可以互相赋值。

  • 二维数组
// 声明一个二维整型数组,两个维度分别存储 4 个元素和 2 个元素
var array [4][2]int
// 使用数组字面量来声明并初始化一个二维整型数组
array := [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}}
// 声明并初始化外层数组中索引为 1 个和 3 的元素
array := [4][2]int{1: {20, 21}, 3: {40, 41}}
// 声明并初始化外层数组和内层数组的单个元素
array := [4][2]int{1: {0: 20}, 3: {1: 41}}
  • 函数间传递数组

由于Go语言函数之间传递变量是,总是按值传递。这就导致无论数组有多长,再传递给函数中是都会完整的拷贝一份,内存开销大。比较优雅的做法是,使用指针实现函数间传递数组。

// 分配一个8MB的数组
var array [1e6]int

// 将数组的地址传递给函数foo
foo(&array)

// 函数foo接受一个指向100万个整型值的数组的指针
func foo(array *[1e6]int) {
    ...
}

切片

  • 切片的内部实现和基础功能
    • 类似于动态数组,按需自动增长和缩小
    • append函数实现动态增长,,cap返回容量(len返回长度,同样可应用于数组和通道)
    • 切片可以多次切片
    • 包含三个字段(指向底层数组的指针、切片访问的元素个数、切片允许增长到的元素个数)即地址指针、长度和容量
  • 切片的创建和初始化
  1. 使用make创建

使用make创建切片时,需要传入一个参数指定切片的长度

// 创建一个字符串切片
// 其长度和容量都是 5 个元素
slice := make([]string, 5)

如果只指定长度,那么切片的容量和长度相等。可分别指定长度和容量,不允许创建容量小于长度的切片。

// 创建一个整型切片
// 其长度为 3 个元素,容量为 5 个元素
slice := make([]int, 3, 5)
  1. 使用切片字面量创建

切片字面量创建和数组类似,区别在于[]中是否指定了值,如果指定了,那就是数组,没有指定就是切片。

// 创建字符串切片
// 其长度和容量都是 5 个元素
slice := []string{"Red", "Blue", "Green", "Yellow", "Pink"}

// 创建一个整型切片
// 其长度和容量都是 3 个元素
slice := []int{10, 20, 30}

// 创建字符串切片
// 使用空字符串初始化第 100 个元素
slice := []string{99: ""}
  • nil和空切片

声明切片时不做任何初始化,就会创建一个nil的切片。在需要描述一个不存在的切片时,nil 切片会很好用。

// 创建nil整形切片
var slice []int

利用初始化,通过声明一个切片可以创建一个空切片。想表示空集合时空切片很有用.

// 使用 make 创建空的整型切片
slice := make([]int, 0)
// 使用切片字面量创建空的整型切片
slice := []int{}
  • 创建和使用切片,一下代码获得的新的切片和原切片共享一个底层数组。
// 创建一个整型切片
// 其长度和容量都是 5 个元素
slice := []int{10, 20, 30, 40, 50}
// 创建一个新切片
// 其长度为 2 个元素,容量为 4 个元素
newSlice := slice[1:3]

// 输出为:20,30

对底层数组容量是 k 的切片 slice[i:j]来说
长度: j - i 
容量: k - i 
  • 切片增长
// 创建一个整型切片
// 其长度和容量都是 5 个元素
slice := []int{10, 20, 30, 40, 50}

// 创建一个新切片
// 其长度为 2 个元素,容量为 4 个元素
newSlice := slice[1:3]

// 使用原有的容量来分配一个新元素
// 将新元素赋值为 60
newSlice = append(newSlice, 60)

如果底层数组没有足够的可用容量,append函数会创建一个新的底层数组(在切片的容量小于 1000 个元素时,总是会成倍地增加容量。一旦元素个数超过1000,容量的增长因子会设为 1.25,也就是会每次增加 25%的容量。随着语言的演化,这种增长算法可能会有所改变。
),将被引用的现有的值复制到新的数组里,再追加新的值。

// 创建一个整型切片
// 其长度和容量都是 4 个元素
slice := []int{10, 20, 30, 40}

// 向切片追加一个新元素
// 将新元素赋值为 50
newSlice := append(slice, 50)
  • 创建切片时的3个索引

第三个索引可以用来控制切片的容量

// 创建字符串切片
// 其长度和容量都是 5 个元素
source := []string{"Apple", "Orange", "Plum", "Banana", "Grape"}

// 将第三个元素切片,并限制容量
// 其长度为 1 个元素,容量为 2 个元素
slice := source[2:3:4]


对于 slice[i:j:k] 或 [2:3:4]
长度: j – i 或 3 - 2 = 1
容量: k – i 或 4 - 2 = 2
  • 创建切片时拥有新的底层数组

如果在创建切片时设置切片的容量和长度一样,就可以强制让新切片的第一个 append 操作创建新的底层数组,与原有的底层数组分离。新切片与原有的底层数组分离后,可以安全地进行后续修改。

// 创建字符串切片
// 其长度和容量都是 5 个元素
source := []string{"Apple", "Orange", "Plum", "Banana", "Grape"}

// 对第三个元素做切片,并限制容量
// 其长度和容量都是 1 个元素
slice := source[2:3:3]

// 向 slice 追加新字符串
slice = append(slice, "Kiwi")
  • append可变参数

append可以在一次调用传递多个追加的值,如果使用...运算符,可以将一个切片的所有元素追加到另一个切片里。

// 创建两个切片,并分别用两个整数进行初始化
s1 := []int{1, 2}
s2 := []int{3, 4}
// 将两个切片追加在一起,并显示结果
fmt.Printf("%v\n", append(s1, s2...))
Output:
[1 2 3 4]
  • 迭代切片

使用range关键字迭代切片里面的元素。需要注意的是,关键字range返回两个值,第一个值是当前迭代的索引位置,第二个是该位置对应元素的一份副本(不是直接返回元素的引用,迭代过程中使用的是同一个地址不断赋值)。

同样可以使用传统的for循环迭代切片。

  • 多维切片
// 创建一个整型切片的切片
slice := [][]int{{10}, {100, 200}}
  • 在函数间传递切片

在64位架构的机器上,一个切片需要24字节的内存:指针字段需要8字节,长度和容量字段分别需要8字节。由于底层数组不属于切片本身,所以将切片复制到任意函数的时候,对底层数组大小都不会有影响。

// 分配包含 100 万个整型值的切片
slice := make([]int, 1e6)

// 将 slice 传递到函数 foo
slice = foo(slice)

// 函数 foo 接收一个整型切片,并返回这个切片
func foo(slice []int) []int {
...
return slice
} 

映射

  • 映射创建和初始化
  1. 使用make声明映射
// 创建一个映射,键的类型是 string,值的类型是 int
dict := make(map[string]int)

// 创建一个映射,键和值的类型都是 string
// 使用两个键值对初始化映射
dict := map[string]string{"Red": "#da1337", "Orange": "#e95a22"}
  1. 更常用映射字面量。映射的初始长度会根据初始化时指定的键值对的数量来确定。映射的可以是内置的类型或结构类型,但不可以时具有引用语义的类型。
  • 使用映射

    • 为映射赋值
    // 创建一个空映射,用来存储颜色以及颜色对应的十六进制代码
    colors := map[string]string{}
    
    // 将 Red 的代码加入到映射
    colors["Red"] = "#da1337"
    
    • nil映射,通过声明一个为初始化的映射来创建一个nil的映射,nil映射不能用于键值对的存储。
  • 从映射取值的两种操作

    • 从映射获取值并且判断键是否存在
    // 获取键 Blue 对应的值
    value, exists := colors["Blue"]
    
    // 这个键存在吗?
    if exists {
      fmt.Println(value)
    } 
    
    • 值返回对应的值,并通过该值判断键是否存在
    // 获取键 Blue 对应的值
    value := colors["Blue"]
    
    // 这个键存在吗?
    if value != "" {
      fmt.Println(value)
    }
    
  • 使用range迭代映射

range返回的是key、value。

// 创建一个映射,存储颜色以及颜色对应的十六进制代码
colors := map[string]string{
    "AliceBlue": "#f0f8ff",
    "Coral": "#ff7F50",
    "DarkGray": "#a9a9a9",
    "ForestGreen": "#228b22",
} 

// 显示映射里的所有颜色
for key, value := range colors {
    fmt.Printf("Key: %s Value: %s\n", key, value)
} 
  • 删除映射delete函数
// 删除键为 Coral 的键值对
delete(colors, "Coral")

// 显示映射里的所有颜色
for key, value := range colors {
    fmt.Printf("Key: %s Value: %s\n", key, value)
} 
  • 在函数见传递映射
    当传递映射给一个函数,不会制造出该映射的一个副本。但在对这个映射做了修改时,所有对这个映射的引用都会察觉到这个修改。

相关文章

  • go语言数组、切片、映射

    go的一些语法有点晦涩,这些很基础,做一下笔记 数组 数组声明 数组声明初始化 切片 切片的声明 切片的追加 切片...

  • Go语言数组、切片、映射

    数组 声明和初始化 访问指针数组的元素 相同类型(数组长度和每个数组元素类型相同)的数组变量可以互相赋值。 二维数...

  • Go语言切片

    // //Go语言切片 // /* // go语言切片是对数组的抽象 // Go 数组的长度不可改变,在特定场景中...

  • Go语言 参数传递究竟是值传递还是引用传递的问题分析

    之前我们谈过,在Go语言中的引用类型有:映射(map),数组切片(slice),通道(channel),方法与函数...

  • 七、Go切片

    七、Go语言切片(Slice) Go 语言切片是对数组的抽象。 Go 数组的长度不可改变,在特定场景中这样的集合就...

  • Go 语言程序设计——集合类型(1)

    Go语言的所有内置类型:数组、切片和映射 值、指针和引用类型 值在传递给函数或者方法的时候会被复制一次 Go语言中...

  • Go语言入门——数组、切片和映射

    Go语言入门——数组、切片和Map 按照以往开一些专题的风格,第一篇一般都是“从HelloWorld开始” 但是对...

  • Go语言第3天 - 常用数据类型

    以下内容部分参考自Go语言基础数据类型Go语言中的数组切片:特立独行的可变数组Go语言数据类型-数组Go标准容器之...

  • Go In Action --- 数组、切片、映射

    小记 符号解释 名词翻译 关键字 数组 数组是一个长度固定的数据结构,用于存储一段具有相同的类型的元素的连续块。数...

  • Go 切片和数组

    数组 go创建数组和 c 语言类似,有如下两种方式: 切片 切片声明和数组类似,只是没有传递长度 创建二维切片,并...

网友评论

      本文标题:Go语言数组、切片、映射

      本文链接:https://www.haomeiwen.com/subject/bcwvgctx.html