go语言数组的细枝末节

栏目: IT技术 · 发布时间: 5年前

内容简介:数组 的类型名是 [n ]elemetType ,其中 n 是数组长度, elementType 是数组元素类型 。 数组一般在创建时通过字面量初始化, 单独声明一个数组类型变量而不进行初始化是没有意义的。编译运行结果

go语言数组的细枝末节

1. 内部实现

Go 语言里,数组是一个长度固定的数据类型,用于存储一段具有相同的类型元素的连续块。存储的类型可以是内置类型,也可以是自定义类型。

数组是一种非常有用给的数据结构,因为其占用的内存是连续分配的。 由于内存连续,CPU能把正在使用的数据缓存更久的时间。而且内存连续很容易计算索引,可以快速访问数组里的任意数据。

在Go语言中,数组是一种类似于整形,浮点型,字符串的 基本数据类型 ,区别于C++语言的是, Go语言的数组在函数传参时是值传递的,因此要想通过某个函数修改数组的值,就必须通过传入数组的指针来实现 ,实际上Go语言中的所有函数传参都是值传递。

2. 声明和初始化

数组 的类型名是 [n ]elemetType ,其中 n 是数组长度, elementType 是数组元素类型 。 数组一般在创建时通过字面量初始化, 单独声明一个数组类型变量而不进行初始化是没有意义的。

// 声明  
    var arr0 [3] int // 声明一个有两个类型的数组,但元素默认值都是0  
    arr1 := [...] float64{7.0, 8.1, 9.2} // [...]后面跟字面量初始化列表  

    // 初始化  
    arr2 := [3]int {1, 2, 3}   // 指定长度和初始化字面量  
    arr3 := [...]int {1, 2, 3}  // 不指定长度,但由后面的初始化列表  
    arr4 := [3]int {1:1, 2:3}   // 指定总长度,并通过索引值进行初始化,没有初始化的元素使用默认值  
    arr5 := [...]int {2:2, 5:4} // 不指定总长度,通过索引值进行初始化,没有初始化的元素使用默认值  
      // 数据长度由最后一个索引的元素值确定  
    fmt.Println("arr0:", arr0)  
    fmt.Println("arr1:", arr1)  
    fmt.Println("arr2:", arr2)  
    fmt.Println("arr3:", arr3)  
    fmt.Println("arr4:", arr4, "len=", len(arr4))  
    fmt.Println("arr5:", arr5, "len=", len(arr5))

编译运行结果

arr0: [0 0 0]
    arr1: [7 8.1 9.2]
    arr2: [1 2 3]
    arr3: [1 2 3]
    arr4: [0 1 3] len= 3
    arr5: [0 0 2 0 0 4] len= 6

    Process finished with exit code 0

3. 数组的特点

  • 数组创建完长度就固定了,不能再追加元素
  • 数组是值类型的,数组赋值或作为函数参数都是值拷贝
  • 数组长度是数组类型的组成部分,[10]int和[20]int表示不同的类型
  • 可以根据数组创建切片(切片后面文章会介绍)
  • 在函数间传参是值传递的

4. 数组元素的访问

arr := [...]int{1, 2, 3}
    // 方式一
    for i:=0; i<len(arr); i++ {
        fmt.Printf("arr[%d] = %d\n", i, arr[i])
    }
    // 方式二
    for k, v := range arr {
        fmt.Printf("arr[%d] = %d\n", k, v)
    }

5. 指针数组

// 声明包含5个元素的指向整数的数组  
    // 用整形指针初始化索引为0和1的数组元素  
    arr := [2]*int{0: new(int), 1: new(int)}  

    // 为索引0和1的元素赋值  
    *arr[0] = 1;  
    *arr[1] = 2;  

    fmt.Println(arr)  
    for _, v := range arr {  
       // 对每个地址解引用,得到其指向的值  
      fmt.Println(\*v)  
    }

代码编译运行结果如下:

[0xc00000a0c8 0xc00000a0e0]
    1
    2

指针数组的内存分布如下图所示:

go语言数组的细枝末节

6. 数组之间的赋值

在Go语言里,数组是一个值。这意味着数组可以用在赋值操作中。 变量名代表整个数组(和C++不同) ,同一类型的数组可以赋值给另一个数组,代码如下:

// 声明第一个包含5个元素的字符串数组  
    var arr1 [5] string  
    // 声明第二个包含5个元素的字符串数组并并初始化  
    arr2 := [...]string{"Red", "Blue", "Green", "Yellow", "Pink"}  
    // 把arr2复制到arr1  
    arr1 = arr2

复制之后,两个数组完全一样,如下图所示。

go语言数组的细枝末节

前面已经说过,数组变量的类型包括数组长度和每个元素的类型。只有这两部分都相同的数组,才是类型相同的数组,才能互相赋值,否则会报编译错误。

7. 指针数组的赋值

package main

import "fmt"

func main() {
    // 声明第一个包含3个元素的指向字符串的指针数组
    var arr1 [3] *string

    // 声明第二个包含3个元素的指向字符串的指针数组
    arr2 := [...]*string{new(string), new(string), new(string)}

    // 为每个元素赋值
    *arr2[0] = "Red"
    *arr2[1] = "Blue"
    *arr2[2] = "Green"

    // 把arr2复制到arr1
    arr1 = arr2

    fmt.Println(arr1)
    // 打印每个指针元素指向的值
    for k, v := range arr1 {
        fmt.Printf("arr[%d] = %s\n", k, *v)
    }
}

编译运行结果如下。

arr1: [0xc0000441f0 0xc000044200 0xc000044210]
    arr[0] = Red
    arr[1] = Blue
    arr[2] = Green

    Process finished with exit code 0

赋值之后,两个数组指向同一个字符串,如下图所示。

go语言数组的细枝末节

8.多维数组

数组本身只有一个维度,但可以组合多个维度创建多维数组,代码如下所示。

package main

    import "fmt"

    func main() {
        // 声明一个二维整形数组,两个维度分别存储4个元素和2个元素
        var arr1 [4][2]int
        // 使用数组字面量来声明并初始化一个二维数组
        arr2 := [4][2] int{{1, 2}, {3, 4}, {5, 6}, {7, 8}}
        // 声明并初始化外层数组中索引为1和3的元素
        arr3 := [4][2] int{1: {30, 40}, 3: {50, 60}}
        // 声明并初始化外层数组和内层数组的单个元素
        arr4 := [4][2] int{1: {0: 10}, 2: {1: 40}}
        fmt.Println("arr1:", arr1)
        fmt.Println("arr2:", arr2)
        fmt.Println("arr3:", arr3)
        fmt.Println("arr4:", arr4)
    }

编译运行结果如下

arr1: [[0 0] [0 0] [0 0] [0 0]]
    arr2: [[1 2] [3 4] [5 6] [7 8]]
    arr3: [[0 0] [30 40] [0 0] [50 60]]
    arr4: [[0 0] [10 0] [0 40] [0 0]]

    Process finished with exit code 0

9. 在函数间传递数组

根据内存和性能来看,在函数间传递数组是一个开销很大的操作。在函数之间传递变量时,总是以值的方式传递的。如果这个变量是一个数组,意味着整个数组,不管有多长,都会完整复制后传递给函数。

package main

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

    func main() {
        // 分配一个8MB的数组
        var arr [1e6]int

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

现在将数组的地址传入函数,在栈空间分配上只需销毁8字节的内存空间。这个操作会更有效第利用内存,性能也更好。不过要意识到,因为现在传递的是指针,如果改变指针指向的值,会改变共享的内存,如果调用者不期望这种改变,就可能出现问题。

关于go语言数组,就啰嗦这么多了~~

go语言数组的细枝末节

我是lioney,年轻的后端攻城狮一枚,爱钻研,爱技术,爱分享。 个人笔记,整理不易,感谢阅读、点赞和收藏。 文章有任何问题欢迎大家指出,也欢迎大家一起交流后端各种问题!


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Tagging

Tagging

Gene Smith / New Riders / 2007-12-27 / GBP 28.99

Tagging is fast becoming one of the primary ways people organize and manage digital information. Tagging complements traditional organizational tools like folders and search on users desktops as well ......一起来看看 《Tagging》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具