go--数组

数组的定义

数组是用来存储相同唯一类型的,一组已编号且长度固定的序列

数组的特点

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

数组声明需要指定元素类型及元素个数,语法格式如下:

var arr_name [num]arr_type

例如

package main

import "fmt"

func main() {

   //三种定义数组的方式
   var age1 [5]int = [5]int{22, 32, 43, 14, 15} //声明长度为5 类型为 int 的数组
   var age2 = [5]int{11, 32, 43, 14, 15}        //声明并初始化,写长度
   age3 := [5]int{33, 32, 43, 14, 15}

   age4 := [...]int{33, 32, 43, 14, 15} // ... 表示数组长度不固定
   fmt.Println(age1)
   fmt.Println(age2)
   fmt.Println(age3)
   fmt.Println(age4)

}

结果

[22 32 43 14 15]
[11 32 43 14 15]
[33 32 43 14 15]
[33 32 43 14 15]

我们在定义数组的时候,也可以给某个索引上的值赋值,没赋值的就使用默认值

package main

import "fmt"

func main() {
   a := [5]int{3: 18} // 给索引为 3 的元素赋值为 18。没赋值的就使用默认值,int 的默认值为 0
   fmt.Println(a)
}

结果

[0 0 0 18 0]

求数组的长度

package main

import "fmt"

func main() {
   a := [...]int{3: 18, 8: 12} // 给索引为 3 的元素赋值为 18,给索引为 8 的元素赋值为 12
   fmt.Println(a)
   fmt.Println(len(a)) // 查看数组的长度,因为索引为 8 的元素有值,所以长度最少为 9
}

结果

[0 0 0 18 0 0 0 0 12]
9

使用 for range 循环数组

package main

import "fmt"

func main() {
   a := [...]string{"aa", "bb", "cc", "张三", "李四"}
   for index, value := range a { // index 为索引,value 为值
      fmt.Println(index, value)
   }
}

结果

0 aa
1 bb
2 cc
3 张三
4 李四

数组是值类型

package main

import "fmt"

func main() {
   a := [3]string{"django", "python", "go"}
   b := [5]string{"php", "javascript", "rust", "java", "vue"}
   fmt.Printf("%T\n", a)
   fmt.Printf("%T\n", b)
}

结果

[3]string
[5]string

如上所示,数组 a 和数组 b 都是数组类型,但是不是同一种类型。从上面的结果可以看到,a 和 b 的长度不一样,所以是不一样的数组类型

在 go 中,数组是值类型,如下

package main

import "fmt"

func printMsg(s [3]string) {
   s[0] = "hi"            // 修改索引为 0 的值
   fmt.Printf("%p\n", &s) // 查看内存地址
   fmt.Println(s)
}

func main() {
   a := [3]string{"django", "python", "go"}
   printMsg(a)            // 调用函数
   fmt.Printf("%p\n", &a) // 查看内存地址
   fmt.Println(a)
}

结果

0xc0000721b0
[hi python go]
0xc000072180
[django python go]

从结果中,我们可以看到,当我们在函数中改变了数组的值后,在函数外面还是原来的值。这是因为在 go 中数组是值类型。在给函数传参的时候,实际上是拷贝了一份数据,可以看出,他们的内存地址是不同的

访问数组元素

  • 数组元素可以通过索引(位置)来读取和赋值
  • 索引从 0 开始
package main

import "fmt"

func main() {

   var arr1 [10]int
   // 根据索引赋值
   for i := 0; i < 10; i++ {
      arr1[i] = i

   }
   // 根据索引查询数据
   for i := 0; i < 10; i++ {
      fmt.Println(arr1[i])

   }
}

结果

0
1
2
3
4
5
6
7
8
9

数组赋值

package main

import "fmt"

func main() {

   var age1 [5]int = [5]int{}
   age1[0] = 18 // 索引从 0 开始
   age1[1] = 23
   age1[2] = 43
   age1[3] = 54
   age1[4] = 55
   //age1[-1]=87  // 错误,数组越界了
   //age1[5]=32   // 错误,数组越界了
   fmt.Println(age1)
}

循环数组

package main

import "fmt"

func main() {

   var age1 [5]int = [5]int{18, 23, 43, 54, 55}

   // 第一种循环
   for i := 0; i < len(age1); i++ {
      fmt.Println(age1[i])
   }

   // 第二种循环,通过 for range
   for i, val := range age1 {
      // i 为索引,val 为数组里的值
      fmt.Println(i, val)
   }
}

结果

18
23
43
54
55
0 18
1 23
2 43
3 54
4 55

指针数组

  • 数组的元素除了是某个类型外,还可以是某个类型的指针
  • new 函数返回一个 TYPE 类型的数据结构划分内存并执行默认的初始化操作,然后返回这个数据对象的指针
package main

import "fmt"

func main() {
   var arr1 [5]*int // 定义了一个数组 arr1,里面有五个 int 类型的指针
   //根据索引赋值
   arr1[0] = new(int) // new 创建的是一个指针地址
   arr1[1] = new(int)
   arr1[2] = new(int)
   arr1[3] = new(int)
   arr1[4] = new(int)
   fmt.Println(arr1) // 打印的是指针的内存地址

   *arr1[0] = 10 // 给数组 arr1 赋值,因为是指针数组,所以需要在 arr1 前面加上 *
   *arr1[1] = 20
   fmt.Println(arr1)     // 打印的是指针的内存地址,取值需要加 *
   fmt.Println(*arr1[1]) // 打印的是具体的值,取值需要加 *
   for i := 0; i < len(arr1); i++ {
      fmt.Printf("[索引:%d 值是: %d]\n", i, *arr1[i])
   }
}

结果

[0xc00001e080 0xc00001e088 0xc00001e090 0xc00001e098 0xc00001e0a0]
[0xc00001e080 0xc00001e088 0xc00001e090 0xc00001e098 0xc00001e0a0]
20
[索引:0 值是: 10]
[索引:1 值是: 20]
[索引:2 值是: 0]
[索引:3 值是: 0]
[索引:4 值是: 0]

数组指针

  • 数组是一个值类型,所有的值类型变量在赋值和作为参数传递时都将产生一次复制操作
  • 从内存和性能上来看,在函数间传递数组是一个开销很大的操作。因为无论这个数组有多长,都会完整复制,并传递给函数
  • 数组指针只需要很小传递
package main

import (
   "fmt"
   "unsafe"
)

func bigArrPoint(arr *[1e6]int64) { // 参数是一个数组的指针
   fmt.Printf("[数组指针复制:大小:%d字节]\n", unsafe.Sizeof(arr))
}

func bigArr(arr [1e6]int64) { // 参数是一个数组
   fmt.Printf("[数组复制:大小:%d字节]\n", unsafe.Sizeof(arr))
}

func main() {

   var arr [1e6]int64 // 定义了一个 1e6 个长度的数组
   bigArr(arr)        // 调用 bigArr
   bigArrPoint(&arr)  //把 arr 的内存地址传给
}

结果

[数组复制:大小:8000000字节]
[数组指针复制:大小:8字节]

多维数组

  • 多维数组的典型用例是平面坐标(二维数组)和三维坐标(三维数组)
  • Golang 的数组本身只有一个维度,但是我们可以组合多个数组从而创建出多维数组
package main

import (
   "fmt"
)

func main() {
   // 定义了一个多维数组, [4]表示有四个元素,[2]每个元素里有两个
   arr1 := [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}}
   fmt.Println(arr1)
   fmt.Println(arr1[3][1]) //
}

结果

[[10 11] [20 21] [30 31] [40 41]]
41

 

posted @ 2024-01-16 23:19  邹邹很busy。  阅读(5)  评论(0编辑  收藏  举报