Go教程(五) 数组

数组是指一系列同一类型数据的集合。数组中包含的每个数据被称为数组元素(element),这种类型可以是任意的原始类型,比如 int、string 等,也可以是用户自定义的类型
一个数组包含的元素个数被称为数组的长度。在 Golang 中数组是一个长度固定的数据类型,数组的长度是类型的一部分,也就是说 [5]int 和 [10]int 是两个不同的类型。Golang 中数组的另一个特点是占用内存的连续性,也就是说数组中的元素是被分配到连续的内存地址中的,因而索引数组元素的速度非常快。

Golang 数组的特点

我们可以把 Golang 数组的特征归纳为以下三点:

  • 固定长度:这意味着数组不可增长、不可缩减。想要扩展数组,只能创建新数组,将原数组的元素复制到新数组。
  • 内存连续:这意味可以在缓存中保留的时间更长,搜索速度更快,是一种非常高效的数据结构,同时还意味着可以通过数值的方式(arr[index])索引数组中的元素。
  • 固定类型:固定类型意味着限制了每个数组元素可以存放什么样的数据,以及每个元素可以存放多少字节的数据。

数组是个固定长度的数据类型,其长度和存储元素的数据类型都在声明数组时确定,并且不能更改。如果需要存储更多的元素,必须先创建一个更长的数组,然后把原来数组里的数据复制到新数组中。
数组占用的内存是连续分配的,比如我们创建一个包含 5 个整数元素的数组:

var arr [5]int

数组的声明与初始化

声明数组声明数组时需要指定数组的长度和数组中元素的类型,比如声明一个包含 5 个元素,类型为 int 的数组:

var arr1 [5]int

这里强调一点,数组的类型是包含数组长度的,因此 [5]int 和 [10]int 是两个不同类型的数组。
在 Go 语言中声明变量时,总会使用对应类型的零值来初始化变量,数组也不例外。当声明数组变量时,数组内的每个元素被初始化为对应类型的零值。比如变量 arr1,它的 5 个元素都被初始化成了 int 类型的零值 0。使用 fmt.Println(arr1) 可以看到数组中元素的值:

package main

import (
  "fmt"
)

func main() {
  arr := make([]int, 5)
  arr[0] = 1
  fmt.Println("hello") // 输出[ 1 0 0 0 0]
  fmt.Println(arr)
  var a [5]string
  a[0] = "a"
  fmt.Println(a)    // 输出 [a    ]
}

使用字面量初始化数组我们可以通过字面量在声明数组的同时快速的初始化数组:

arr2 := [5]int{10,20,30,40,50}

对于这种情况,还可以使用 … 代替数组的长度,让编译器根据实际的元素个数自行推断数组的长度:

arr3 := []int{10,20,30,40,50}

如果设置了数组的长度,还可以通过指定下标的方式初始化部分元素:

// 用具体值初始化索引为 1 和 3 的元素
arr4 := [5]int{1:20,3:40}

访问与修改数组元素

和其它类 C 语言一样,Go 语言数组通过数组下标(索引位置)来读取或者修改数组元素。下标(索引)从 0 开始,第一个元素的索引为 0,第二个索引为 1,依次类推。元素的数目(数组长度)必须是固定的并且在声明数组时就指定(编译器需要知道数组的长度以便分配内存),数组长度最大为 2G。

访问数组元素对于数组 arr 来说,第一个元素就是 arr[0],第二个元素是 arr[1],最后一个元素则是 arr[len(arr)-1]。下面的代码定义一个整型数组,然后通过 for 循环打印数组中的每个元素:

arr1 := [5]int{10, 20, 30, 40, 50}
  for i := 0; i < len(arr1); i++ {
    fmt.Printf("At index %d is %d\n", i, arr1[i])
  }

输出结果如下

At index 0 is 10
At index 1 is 20
At index 2 is 30
At index 3 is 40
At index 4 is 50

除了使用 len() 函数通过索引遍历数组,还可以使用更方便的 range,结果都是一样的:

for index, value := range arr1 {
    fmt.Printf("At index %d is %d\n", index, value)
  }

输出结果同上面完全一致

修改数组元素要修改单个元素的值,直接通过下标访问元素并赋值就可以了:

arr1[0] = 1

指针数组

数组的元素除了是某个类型外,还可以是某个类型的指针,下面声明一个所有元素都是指针的数组,然后使用 * 运算符就可以访问元素指针所指向的值:

arr := [5]*int{0: new(int), 1: new(int)}

new(TYPE) 函数会为一个 TYPE 类型的数据结构划分内存并执行默认的初始化操作,然后返回这个数据对象的指针,所以 new(int) 表示创建一个 int 类型的数据对象,同时返回指向这个对象的指针。

arrPointer := [5]*int{new(int)}
*arrPointer[0] = 2
fmt.Println(*arrPointer[0]) // 输出2
fmt.Println(arrPointer[0]) // 输出 0xc000014118 这是一个内存地址

数组是值类型

在 Golang 中,数组是值类型,这意味着数组也可以用在赋值操作中。变量名代表整个数组,同类型的数组可以赋值给另一个数组:

  var arr2 [5]int
  arr2 = arr1
  arr1[3] = 5         // 修改arr1
  fmt.Println(arr2)  // 这里仍然输出 [10 20 30 40 50] 因为是值类型所以不受影响

把数组赋值给其它数组时,实际上是完整地复制一个数组。

数据是指针类型

如果数组是一个指针型的数组,那么复制的将是指针,而不会复制指针所指向的对象。看下面的代码

  arrPointer := [5]*int{new(int)}
  *arrPointer[0] = 2
  fmt.Println(*arrPointer[0])
  fmt.Println(arrPointer[0])

  var arr3 [5]*int
  arr3 = arrPointer
  fmt.Println(len(arr3))
  for index, value := range arr3 {
    fmt.Printf("== At index %d address is %h\n", index, value)
  }

  for i := 0; i < len(arr3); i++ {
    if arr3[i] != nil { // 是空指针会发生panic需要提前判断
      fmt.Println("at address", arr3[i], " value = ", *arr3[i])
    }
  }

结果如下

== At index 0 address is %!h(*int=0xc0000aa0c8)
== At index 1 address is %!h(*int=<nil>)
== At index 2 address is %!h(*int=<nil>)
== At index 3 address is %!h(*int=<nil>)
== At index 4 address is %!h(*int=<nil>)
at address 0xc0000aa0c8  value =  2
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值