GO学习笔记——数组(10)

今天来看看数组。C/C++还有其他一些语言基本都用方括号 [] 来表示数组,另外C++还有array数组容器以及vector动态顺序表(这其实相当于后面要说到的切片)。

当然了,今天的主题是GO的数组。

GO也是用方括号 [] 来表示数组,先来看下它的一些定义方式

func main() {
	//1. 声明了一个包含5个int的数组,每个元素被赋零值0
	var arr1 [5]int

	//2. 定义了一个包含5个int的数组,前三个元素分别被赋值为1,2,3,后两个元素被赋零值0
	arr2 := [5]int{1,2,3}

	//3. 用...来省略个数,这里就是定义了一个包含5个int的数组,编译器帮我们计算这个数组的大小
	arr3 := [...]int{1,2,3,4,5}

	//4. 定义一个四行五列的二维数组,且第一行被赋值为全1
	arr4 := [4][5]int{{1,1,1,1,1}}

	fmt.Println(arr1)
	fmt.Println(arr2)
	fmt.Println(arr3)
	fmt.Println(arr4)
}
[0 0 0 0 0]
[1 2 3 0 0]
[1 2 3 4 5]
[[1 1 1 1 1] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0]]

以上几种定义方式是较为常见的定义方式,总结一下

  • 遵循GO基本的变量命名规则,数组名现在前面,数组的元素类型写在后面
  • 数组的元素个数写在类型前面,用 [n]type 表示
  • []内可用...表示让编译器计算数组个数

下面来说一些数组使用的技巧


遍历数组的range关键字

一般在C语言中,遍历一个数组都是用类似如下的遍历方式,GO语言中也是一样

func main() {
	arr := [5]int{1,2,3,4,5}
	for i := 0; i < 5; i++ {
		fmt.Print(arr[i])
	}
}
//输出结果
12345

 但是GO语言中有一个专门用于遍历数组的关键字range,可以方便我们遍历数组,用法如下

func main() {
	arr := [5]int{1,2,3,4,5}
	for i,v := range arr {
		fmt.Printf("第%d个元素是: %d\n",i,v)
	}
}

//输出结果
第0个元素是: 1
第1个元素是: 2
第2个元素是: 3
第3个元素是: 4
第4个元素是: 5

这就有点类似于C++11中引入的范围for循环了,其实很多语言都引入了这种类似的范围for循环来简化传统for循环的写法。

range返回两个值,它返回的第一个参数是索引,第二个参数是该索引的值,所以我们可以像上面一样用两个变量来接收它们。

正式因为range能够同时返回索引以及索引的值的特性,所以在遍历数组的时候,基本上都使用range来遍历,方便直观。

当然,这里有一个问题,有时候我们只想要索引的值,而不想要该索引,那么怎么办,那么就可以使用下划线_了。

func main() {
	//用下划线来不接收索引,而只接收索引的值
	arr := [5]int{1,2,3,4,5}
	for _,v := range arr {
		fmt.Println(v)
	}
}

//输出结果
1
2
3
4
5

如果只要索引,那么就不用这么麻烦了,直接用一个返回值来接收就可以了

func main() {
	//用下划线来不接收索引,而只接收索引的值
	arr := [5]int{1,2,3,4,5}
	for i := range arr {
		fmt.Println(arr[i])
	}
}

//输出结果
1
2
3
4
5

数组的长度

可以通过len函数来获得数组的长度

func main() {
	arr := [5]int{1,2,3,4,5}
	fmt.Println(len(arr))
}

输出结果

5

数组是值类型的

先上一段C++的代码

#include <iostream>
using namespace std;

void func(int *arr){
    arr[0] = 100;    //这里将数组的第一个元素改为100
}
int main(){
    int arr[] = {1,2,3,4,5};
    func(arr);
    for(int i = 0; i < 5; ++i)
        cout << arr[i] << " ";
    cout << endl;
    return 0;
}

输出结果

100 2 3 4 5 

可以看到,我们将这个数组作为参数传给了函数func,并在函数体内修改了第一个数组元素的值,我们发现函数执行完以后,原来的数组的第一个元素被改变了,这就是引用类型的。C++函数参数类型要传数组的时候,会弱化成数组首元素的地址传进去,也就是说,函数拿到的是原来的数组的首元素的地址,也就是一个指针,这样进行改动,当然会改变原数组的值。

但是GO就不是了,GO的数组是值类型的。先把上述代码改成GO版本的。

//注意下面必须是[5]int,GO编译器认为[3]int和[5]int是两种不同的数据类型
func fun(arr [5]int){
	arr[0] = 100
}

func main() {
	arr := [5]int{1,2,3,4,5}
	fun(arr)
	for i := range arr {
		fmt.Printf("%d ",arr[i])
	}
}

输出结果

1 2 3 4 5

这边GO就没有对元素进行改变,也就是说,在GO语言中,数组是值类型的。其实,在数组传参的时候,因为只有值传递,所以是拷贝了一个一模一样的数组作为临时的参数传给函数的,所以这是两个数组,临时数组改变不影响原来的数组。

那么我要是想改变原来的数组内容怎么办呢?很简单,用指针,传参数的时候传一个指针就好了。

//注意下面必须是[5]int,GO编译器认为[3]int和[5]int是两种不同的数据类型

func fun(arr *[5]int){    //这里传一个指针
	arr[0] = 100
}

func main() {
	arr := [5]int{1,2,3,4,5}
	fun(&arr)    //这里传数组的的地址
	for i := range arr {
		fmt.Printf("%d ",arr[i])
	}
}

输出结果

100 2 3 4 5 

可以看到,这样原数组就被改变了。

所以,这里关于数组给函数传参的时候的用法,需要注意,到底是要传值呢,还是要传指针,需要根据程序来不同设计。

但是,这样传参数还是很麻烦啊,我们必须得提前知道数组的个数,因为不同个数的数组是被认为不同类型的。

所以在GO语言中一般不直接使用数组,而是使用切片,关于切片的部分,下一章再来讲。

猜你喜欢

转载自blog.csdn.net/lvyibin890/article/details/83278109