侧边栏壁纸
  • 累计撰写 47 篇文章
  • 累计收到 0 条评论

GoLang 数组与内存布局

2023-1-12 / 0 评论 / 171 阅读
温馨提示:
本文最后更新于 2023-1-12,已超过半年没有更新,若内容或图片失效,请留言反馈。

数组(Array) - 定义说明

在 Golang 中数组是一个 值类型。如果将数组作为函数的参数类型,则在函数调用时该参数将发生数据复制。因此,在函数体中无法修改传入的数组的内容,因为函数内操作的只是所传入数组的一个副本。

我简单描述下数组的使用姿势和演示说明

package main

import "fmt"

func main()  {
  /*
    1) 四种初始化数组的方式

      var arr1 [3]int = [3]int{1, 2, 3}
      var arr2 = [3]int{1, 2, 3}
      var arr3 = [...]int{1, 2, 3}      // 程序自动判断数组长度
      var arr4 = [3]string{1: "tom", 2: "marry", 0: "jack"}

    2) 常规遍历数组

      var arr = [3]int{1, 2, 3}
      for i := 0; i < len(arr); i++ {
        ...
      }

    3) for-range 结构遍历数组

      var arr = [3]int{1, 2, 3}
      for index, value := range arr {
        ... 
      }

      说明 
        1. 第一个返回值 index 是数组的下标
        2. 第二个 value 是该下标位置对应的值
        3. 他们都是仅在 for 循环内部可见的局部变量
        4. 遍历数组元素的时候, 如果不想使用下标 index, 可以直接把下标 index 标为下划线 _ 表示
  */

    var (
        arr [5]int          // 数组长度是定长的(固定的), 当我们定义完数组后, 数组的各个元素的默认值都是0
    )

    arr[0], arr[1], arr[2], arr[3], arr[4] = 2, 3, 10, 21, 23

    arrValue := 0
    for i := 0; i < len(arr); i++ {
        arrValue += arr[i]
    }

    fmt.Println(arrValue)   // 输出: 59
}

数组使用的注意事项和细节

  1. 数组是多个 相同类型 数据的集合, 一个数组一旦声明/定义, 其 长度是固定的, 不能动态变化。(如果要动态变化, 可以使用切片)
  2. 数组中的元素可以是任何数据类型, 包括值类型和引用类型, 但是 不能混用
  3. 数组创建后, 如果没有赋值, 有默认值(零值)。
  4. 数组的下标都是从 0 开始的
  5. 数组的下标必须在指定的范围内使用, 否则报 panic 数组越界, 比如: var arr [5]int 则有效下标为 0-4
  6. Go 的数组属 值类型, 在默认情况下是值传递, 因此会进行值拷贝, 数组间不会相互影响
  7. 如果想在其他函数中去修改原来的数组值, 可以使用引用传递(指针方式) - [可以自行了解下栈原理], 例如:

    var arr [3]int

    func updateArr(arr [3]int) {

        (
    arr)[0] = 10   // arr[0] = 10

    }

    updateArr(&arr) // 此时 arr 变量的内容为 {10, 0, 0}, 通过指针方式将数组数据修改
  8. 长度是数组类型的一部分, 在传递函数参数的时候, 需要考虑数组的长度。

从使用上来说没有什么难度, 在这也就不细说, 我将把重点放在内存原理上。

我们看看上述代码的数组在内存里是怎么存放的

从上面的内存图我们可以看到:

  • 数组变量 arr 的内存地址和 数组下标为0 的内存地址是一样的, 由此分析出 数组的第一个元素内存地址就是数组变量的内存地址, 这个应该不会太难理解, 因为数组的第一个元素标志着该数组的存在。
  • 可以看到这5个元素的内存地址其实是有规律的
    元素1 0xc00001a0c0
    元素2 0xc00001a0c8
    元素3 0xc00001a0d0
    元素4 0xc00001a0d8
    元素5 0xc00001a0e0

    尾数都是 0 和 8, 当尾数到 8 时, 前位数 进1, 比如 c 进 d, 2 进 3 ...
    主要原因就是因为 int 类型是 8字节 的。如果数组是其他的数据类型也是一样, 根据不同的数据类型占用的字节数 满字节后进1。 (例如: int8 是占用1个字节, int16 是占用2个字节, string 是占用16个字节, 你可以通过 unsafe.Sizeof(arr) 函数查看字节占用)
    如果有第六个元素, 那么它的地址应该是 0xc00001a0e8

好了, 就先介绍到这。

评论一下?

OωO
取消