go语言数组的细枝末节

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

内容简介:数组 的类型名是 [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,年轻的后端攻城狮一枚,爱钻研,爱技术,爱分享。 个人笔记,整理不易,感谢阅读、点赞和收藏。 文章有任何问题欢迎大家指出,也欢迎大家一起交流后端各种问题!


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

查看所有标签

猜你喜欢:

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

C语言常用算法分析

C语言常用算法分析

明日科技 / 2012-1 / 39.80元

《C语言学习路线图•C语言常用算法分析》共分为4篇,第1篇为算法基础篇,包括程序之魂——算法、数据结构基础、查找与排序算法、基本算法思想等内容;第2篇为常用算法篇,包括数学算法、矩阵与数组问题、经典算法等内容;第3篇为趣味算法篇,包括数学趣题、逻辑推理题等内容;第4篇为算法竞技篇,包括计算机等级考试算法实例、程序员考试算法实例、信息学奥赛算法实例等内容。 《C语言学习路线图•C语言常用算法分......一起来看看 《C语言常用算法分析》 这本书的介绍吧!

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具