数组
作为一种新兴的语言,如果仅仅是为了某种特定的用途,那么可能其内置类型不是很多,仅需要能够完成基本功能即可。 但是 Go 不仅支持几乎所有语言都支持的简单数据类型(比如整型和浮点型等)外,还支持一些其他的高级类型, 比如 map 类型,要知道这些类型在其他语言中都是通过包的形式引入的外部数据类型。
slice 类似于 C++ STL 中的 vector,在 Go 中也是一种内置的数据类型作为动态数组来使用。
既然绝大多数开发者都需要用到这个类型,为什么还非要每个人都写一行 import 语句来包含一个库? 当然,可能有人会提到 Go 没有泛型等等,只要是必要的功能,相信后期都会加上去的。
相较于其他编程语言,Go 语言对于某些方面可能算是非常好的了。 例如,Java 生态不错,但是基本上多数都是使用的老版本 1.6 1.8 这样的,并不会一味追求更新的版本。 不过说回来,可能是因为追求新特性的用户都去 Scala 了吧。 C++ 标准太臃肿了,Go 的诞生就有一部分原因是如此,而且风格、库都是各用各的。
言归正传,来看看 Go 中的数组。
声明、初始化
声明 3 个 int 型变量的数组
var arr [3]int arr[0] = 123 arr[1] = 110 arr[2] = 234
定义数组时为数组元素赋值
var arr [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
为部分元素赋值
var arr [10]int = [10]int{1, 2, 3, 4, 5}
指定下标赋值
var arr [10]int = [10]int{1: 10, 4: 20, 6: 30}
根据元素个数赋值并创建数组
var arr [4]int = [...]int{1, 2, 3, 4}
var 写多了的确挺烦的
这种声明方式已经很贴近 slice 了,不过还是留到后面的篇幅在做记录吧
arr := [3]int{1, 22, 333}
arr := [...]int{1, 2, 3, 4}
arr := [5]int{1:1,3:4}
- 多维数组
var arr [3][4]int
arr := [3][4]int{
{0, 1, 2, 3},
{4, 5, 6, 7},
{8, 9, 10, 11},
}
访问修改
访问单个元素
arr := [6]int{100,200,300,400,500,600} fmt.Printfln(arr[0])
for-range 常见的遍历访问方式
arr := [6]int{100,200,300,400,500,600}
for k,v := range arr{
fmt.Printf("arr[%d]=%d\n", k, v)
}
- for 循环访问
arr := [6]int{100,200,300,400,500,600}
for i := 0; i < len(arr); i++ {
fmt.Printf("arr[%d]=%d\n", i, arr[i])
}
- 修改元素
arr := [5]int{1: 1, 3: 4}
arr[1] = 3
同类型的数组可以相互赋值 长度一样,并且每个元素的类型一样的数组,才是同样类型的数组。
array := [5]int{1: 1, 3: 4} var array1 [5]int = array // success var array2 [4]int = array1 // error
指针数组
指针数组和数组本身差不多,只不过元素类型是指针。 创建方式和普通数组不同,需要分配空间,数组元素的默认值为 nil
,访问方式和普通数组差不多加上 *
即可。
arr := [5]*int{1: new(int), 3:new(int)}
*arr[1] = 1
如果你现在给
arr[0]
赋值,会报 painc,原因已经写在上面了,解决办法如下:
arr[0] = new(int) *arr[0] = 2
基本概念
其实前面已经提到了一部分概念,不过还有一些没提到,这里一起总结下来。
- 数组是 元素类型相同 且 长度固定 的存储在内存中数据类型
- 元素类型相同 且 长度固定 的数组才是同样类型的数组
- 数组是值类型。意思就是如果你将一个数组传递给另一个数组,那么,实际上就是整个数组拷贝了一份,函数传递也是如此
- 数组占用连续的内存,索引访问的效率非常高
数组指针和指针数组
x, y := 1, 2
var arr = [...]int{5: 2}
// 数组指针
var pf *[6]int = &arr
// 指针数组
pfArr := [...]*int{&x, &y}
- 数组指针是一个指向数组地址的一个指针
- 指针数组是一个数组内的元素全是指针类型