Go Array

Array 数组

1.初始化

存储结构

编译期间的数组类型:

type Array struct {
	Elem  *Type // element type
	Bound int64 // number of elements; <0 if unknown yet
}

cmd/compile/internal/types.NewArray 函数生成的,该类型包含两个字段,分别是元素类型 Elem 和数组的大小 Bound,这两个字段共同构成了数组类型,而当前数组是否应该在堆栈中初始化也在编译期就确定了。

func NewArray(elem *Type, bound int64) *Type {
   if bound < 0 {
      base.Fatalf("NewArray: invalid bound %v", bound)
   }
   t := New(TARRAY)
   t.Extra = &Array{Elem: elem, Bound: bound}
   t.SetNotInHeap(elem.NotInHeap())
   if elem.HasTParam() {
      t.SetHasTParam(true)
   }
   return t
}
array初始化方式

**编译期函数遍历阶段完成对数组的初始化:**数组是内存中一片连续的区域,需要在初始化时被指定长度,数 组的大小取决于数组中存放的元素大小。对于数组还有一种语法糖, 可以不用指定类型,如arr3:=[…]int{2,3,4},这种声明方式在 编译时自动推断长度。

  • 字面量初始化

    var arr = [4]int{1,2,3,4}
    arr1 := [4]int{1,2,3,4}
    
  • 定长空数组

    var arr2 = [4]int{}
    
  • 语法糖自动推断长度

    arr3 := [...]int{2,3,4}
    
  • 使用new创建数组

    arr4 := new([3]int)
    

anylit函 数用于处理各种类型的字面量。当数组的长度小于4时,在运行时数组 会被放置在栈中,如果当前数组的元素大于四个,cmd\compile\internal\walk\complit.go\anylit 会先获取一个唯一的 staticname,然后调用cmd\compile\internal\walk\complit.go.fixedlit 函数在静态存储区初始化数组中的元素并将临时变量赋值给数组:

image-20220318125607592

编译时初始化:
  1. 声明一块连续的内存空间

  2. 将字面量值依次放入数组中 fixedlit函数将执行数组初始化与赋值的逻辑。

    fixedlit函数伪代码:

    var arr = [3]int{1, 2, 3}
    // 变为:
    var arr [3]int
    arr[0] = 1
    arr[1] = 2
    arr[2] = 3
    

2. 数组的可比性

  1. Go 语言数组在初始化之后大小就无法改变。
  2. 存储元素类型相同、但是大小不同的数组类型在 Go 语言看来也是完全不同的,只有两个条件都相同才是同一类型,也就是说数组的大小也作为类型的描述故 [3]int[5]int 完全是不同的类型。
测试能否对数组重新赋值

如下代码段,企图通过赋值改变arr2数组大小

func main() {
    arr1 := [5]int{1, 2, 3, 4, 5}// arr1为具有5个int元素的数组
    arr2 := [3]int{1, 2, 3} // arr2为具有3个int元素的数组
    arr1 = arr2
    arr1 = [3]int{}
}

使用Go提供的 test 命令对该段代码测试,可以看出无论是使用arr2数组或是空数组对arr1都会在编译期报错:

image-20220318140830230

测试数组的可比性

存在如下4个数组

arr1 := [5]int{1, 2, 3, 4, 5}
arr2 := [3]int{1, 2, 3}
arr3 := [3]int{1, 2, 3}
arr4 := [3]int{4, 4, 4}

尝试使用ifarr1arr2进行对比:

func main() {
    arr1 := [5]int{1, 2, 3, 4, 5}
    arr2 := [3]int{1, 2, 3}
    arr3 := [3]int{1, 2, 3}
    arr4 := [3]int{4, 4, 4}
    if arr1 == arr2 {

    }
}

使用Go提供的 test 命令对该段代码测试:

因为arr1与arr2不是相同的类型所以无法比较

image-20220318141909700

如下代码测试结果为:

true

false

说明,仅当两个数组类型(元素类型、数组大小)且对应下标的元素值相同时,比较结果才为true

func main() {
    arr2 := [3]int{1, 2, 3}
    arr3 := [3]int{1, 2, 3}
    arr4 := [3]int{2, 2, 3}
    if arr3 == arr2 {
        fmt.Println("true")
    } else {
        fmt.Println("false")
    }

    if arr4 == arr2 {
        fmt.Println("true")
    } else {
        fmt.Println("false")
    }
}

3.数组值复制

与C语言中的数组显著不同的是,Go语言中的数组在赋值和函数调 用时的形参都是值复制。

如下代码段

func ChangeArray(arr [3]int) {
	arr[0] = 99
	fmt.Printf("In func arr Addr: %p Value: %v\n", &arr, arr)
}
func main() {
    arr2 := [3]int{1, 2, 3}
	temp := arr2
	fmt.Printf("temp Addr: %p Value: %v\n", &temp, temp)
	fmt.Printf("Befor func arr2 Addr: %p Value: %v\n", &arr2, arr2)
	ChangeArray(arr2)
	fmt.Printf("After func arr2 Addr: %p Value: %v\n", &arr2, arr2) 
}

执行结果:赋值操作、函数传递都会触发数组复制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eJ4peu05-1648342979285)(https://raw.githubusercontent.com/Voryla/myimages/main/deepinJVM/20220318143612.png)]

4.数组的越界访问问题

数组访问越界是非常严重的错误,Go语言中对越界的判断有一部 分是在编译期间类型检查阶段完成的,typecheck1函数会对访问数组 的索引进行验证。

数组越界的判定分为三种情况:

  1. 访问数组的索引是非整数时报错为non-integer array index%v。
  2. 访问数组的索引是负数时报错为invalid array index%v(index must be non-negative)。
  3. 访问数组的索引越界时报错为invalid array index%v(out of bounds for%d-element array)。

总结

​ 数组在初始化时,在不考虑逃逸分析的情况下,如果数组中元素的个数小于或者等于 4 个,那么所有的变量会直接在栈上初始化,如果数组元素大于 4 个,变量就会在静态存储区初始化然后拷贝到栈上;在初始化之后,无法更改数组的大小。仅当两个数组类型(元素类型、数组大小)且对应下标的元素值相同时,比较结果才为true;赋值操作和函数传递都会触发数组复制。

### 回答1: 在 Golang 中,你可以使用数组来存储多个 `time.Time` 类型的值。下面是一个示例代码: ```go package main import ( "fmt" "time" ) func main() { // 创建一个长度为 3 的 time.Time 类型的数组 times := [3]time.Time{} // 初始化数组元素 times[0] = time.Now() times[1] = times[0].Add(time.Hour) times[2] = times[1].Add(time.Hour) // 遍历数组并输出每个元素的值 for _, t := range times { fmt.Println(t) } } ``` 输出结果类似于: ``` 2022-05-16 19:38:27.242514 +0800 CST m=+0.000162443 2022-05-16 20:38:27.242514 +0800 CST m=+3600.000162443 2022-05-16 21:38:27.242514 +0800 CST m=+7200.000162443 ``` 在这个示例中,我们创建了一个长度为 3 的 `time.Time` 类型的数组,并将其初始化为当前时间和当前时间加上一小时和两小时的值。然后,我们遍历数组并输出每个元素的值。 ### 回答2: 在Golang中,可以使用array来存储time.Time类型的数据。time.Time是Golang中用于表示日期和时间的结构体,它包含年、月、日、时、分、秒等信息。 首先,我们可以定义一个包含多个time.Time元素的数组。例如,我们可以定义一个长度为5的数组,存储5个不同的时间: ```go var times [5]time.Time times[0] = time.Now() times[1] = time.Date(2022, time.January, 1, 0, 0, 0, 0, time.UTC) times[2] = time.Date(2022, time.February, 14, 12, 0, 0, 0, time.UTC) times[3] = time.Date(2022, time.March, 8, 9, 30, 0, 0, time.UTC) times[4] = time.Date(2022, time.April, 30, 18, 15, 0, 0, time.UTC) ``` 在上面的例子中,我们使用time.Now()获取当前时间,并使用time.Date()创建了一些特定的时间。这些时间被分别存储在了数组的不同索引位置。 我们还可以通过索引来访问数组中的时间元素,并使用各种时间相关的函数进行操作。例如,我们可以计算两个时间之间的差值: ```go diff := times[1].Sub(times[0]) fmt.Println(diff) // 输出: 8760h0m0s,即一年的小时数 ``` 还可以判断一个时间是否在另一个时间之前或之后: ```go isAfter := times[3].After(times[2]) // 判断times[3]是否在times[2]之后 isBefore := times[4].Before(times[3]) // 判断times[4]是否在times[3]之前 ``` 以上只是使用数组存储time.Time类型数据的一些简单示例。在实际应用中,我们可以根据需要使用数组来存储和操作多个时间。使用Golang的数组和time包,能够便捷地处理时间相关的问题。 ### 回答3: golang中的array是一种固定长度且类型相同的数据结构,而time.Time是golang中用于表示时间的类型。 在golang中,我们可以使用array来创建一个存储time.Time类型的数组。例如,我们可以使用以下代码创建一个包含3个time.Time类型元素的数组: ```go package main import ( "fmt" "time" ) func main() { var dates [3]time.Time dates[0] = time.Now() dates[1] = time.Now().Add(24 * time.Hour) dates[2] = time.Now().Add(48 * time.Hour) fmt.Println(dates) } ``` 在上面的例子中,我们定义了一个长度为3的time.Time类型的数组dates。我们可以使用数组索引来访问每个元素,并对其进行赋值。在这个例子中,我们分别将当前时间、明天的时间和后天的时间分别赋值给了数组的第1个、第2个和第3个元素。最后,我们通过fmt.Println来打印整个数组。 运行上述代码,你会得到一个包含3个时间的数组的输出结果。 总结一下,golang中的array可以用来存储time.Time类型的元素,通过索引来访问和赋值。这样我们就可以方便地使用数组来处理时间相关的数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值