数组注意事项和细节(2)|学习笔记

简介: 快速学习数组注意事项和细节(2)。

开发者学堂课程【GO 语言核心编程-基础语法、数组、切片、Map:数组注意事项和细节(2)】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:https://developer.aliyun.com/learning/course/625/detail/9631


数组注意事项和细节(2)

 

一、数组注意事项和细节

1.数组是多个相同类型数据的组合,一个数组一旦声明/定义了,其长度是固定的,不能动态变化.

2.var arr []int 这时 arr 就是一个 slice 切片,切片后面专门讲解

3.数组中的元素可以是任何数据类型,包括值类型和引用类型,但是不能用。

4.数组创建后,如里设有赋值,有默认值(零值)

数值类型数组:默认值为0

字符串数组:默认值为“”

bool 数组:默认值为 false

5.使用数组的步骤1.声明数组井开辟空间2.给数组各个元素赋值(默认零值) 3.使用数组

6.数组的下标是从0开始的。

7.案例:

//数组的下标是从0开始的

var arr04 [3]string  

//此数组能够访问的下标是从0 -2,没有3

var index int = 3  

//在运行的时候会直接报错,显示越界

arr04[3] = “tom”

//如果直接访问3,则会报错,因为下标是0-2,因此arr04[3]就越界

注意:在编程的时候如果发现有越界的错误,肯定是程序中某一个变量的值超过了它能够访问的下标范围

运行结果如下:

image.png

可以发现在第35行会报错,错误信息为 index out of range,就是越界的意思。

(1)数组下标必须在指定范围内使用,否则报 panic数组越界,比如

var arr [5]int则有效下标为0-4

(2)Go 的数组属值类型,在默认情况下是值传递,因此会进行值拷贝。数组间不会相互影响

//在传递一个数组给一个函数时,其实是把整个数组进行值拷贝,这就意味着在函数中,它的改变并不会影响到外部。

3注意:在很多的编程语言中数组是引用类型,但是在 go 语言中,数组是值类型

8.案例:
//函数

func test01(arr [3]int)  

//定义一个数组,数组类型为[3]int,在go中数组的长度是数组类型的一部分

//在定义数据类型的时候必须把3写上,如果没有写上3的话,则此部分就不是数组,而是切片 slice

//在 go 语言中[3]int 和[4]int 不是同一种数据类型,因为长度不同

arr[0] = 88  

//第一个元素的值为88

arr:=[3]int{11,22,33}

test01(arr)

//调用 test 函数 arr

fmt.Println(“main arr=”,arr)  

//输出arr

(1)问题:此处输出的 arr 是11,22,33还是第一个元素中的值88呢?(将 arr 传入 test 中后,再改变元素值过后,会不会对 arr 有影响)

//由于 Go 的数组属于值类型,所以数组间不会相互影响

2内存图:

当执行 arr:=[3]int{11,22,33}时,arr 处于银色部分的栈中,而 arr 变量会直接指向数组,当执行到 test(arr)函数时,arr 会直接传到 test01函数中,test01会将 arr 进行值拷贝,进行值拷贝操作之后,就意味在内存中出现了一个新的独立的空间,test01栈中会有一份和 main 栈中一样的数组,然后将 test01栈中的数组的第一个元素的值改为88。在test01调用完毕后,继续返回并执行 fmt.Println(arr),此刻的 arr 是 main 栈中的 arr,所以 test01栈中数组的变化对main 栈中的数组没有任何影响。

 image.png

输出效果如下:

image.png

(3)如想在其它函数中,去修改原来的数组,可以使用引用传递(指针方式)

//默认虽然为值传递,但是如果我们引用指针方式传递,也可以成功

如何让数组改变默认传递方式:

4案例:

//函数

func test02(arr *[3]int) {  //添加一个*后,arr就变成了一个指向数组的指针

//fmt.Printf(“arr指针的地址=%p”,arr)  //指针本身有一个地址,可以将其打印出来

//不可以使用以前的方法直接访问数组,需要先将arr的取值符取到,然后再取第一个元素

(*arr)[0] = 88  //!!重要

}

arr :=[3]int{11,22,33}

fmt.Printf(“arr的地址=%p”,&arr)  //打印数组的首地址

test02(&arr)  //将数组的首地址传递给上方的 arr 指针

fmt.Println(“main arr=”,arr)

}

运行结果如下:

image.png

可以发现输出的内容发生了变化,第一个值变成88

5内存图:
当执行完 arr :=[3]int{11,22,33},在主栈中生成数组11,22,33,当调用了 test02后,会开辟一个独立的空间,进入到func test02(arr *[3]int) { 部分,在 test02栈中会出现一个 arr,而且不会进行值拷贝,它会得到数组中的首地址0xc04205e060,此地址会指向 main 栈中的数据,意味着 arr 指向的就是首地址。然后再执行(*arr)[0]=88,就取到一个值 main 栈中数组的值,就将值88赋予给11,执行完毕,返回至 fmt.Println(“main arr=”,arr),打印出88,22,33

输出结果如下:

 image.png

可以看到 arr 指针的地址是0xc042004030,也就是说指针本身拥有一个地址。arr是一个指针,它有一个空间存放的是指向原先数组的首地址,同时它本身存放地址的空间也有一个地址。

image.png

//通过指针传递的效率高,因为在拷贝的时候只是拷贝的变量的副本(地址),地址的数据量小,而上方是进行的值拷贝,如果是一个庞大的值,则非常耗费资源。

//在使用数组时如果想改变外部的数组,就使用指针传递,效果高而且速度快

9.长度是数组类型的一部分,在传递函数参数时需要考虑数组的长度。

1案例1

//认值拷贝

func modify(arr[]int ){  //接收时,arr[]中没有数值

arr[0]= 100

fmt.Println("modify的arr ",arr)

}

func main(){  //定义一个数组

var arr =[…]int[1,2,3]  //数组的长度为3

modify(arr)  //将 arr 传递给 modify

}

答案:编译出现问题,发生报错。因为不能把[3]int 传递给[]int ,它们不是用一种类型,[3]int 是数组,而[]int 是切片

(2)案例2  //认值拷贝

func modify(arr[4]int){

arr[0] = 100

fmt.Println("" modify的arr ",arr)

func main(){

var arr =[...]int{1,2,3]modify(arr)

}

答案:编译错误,因为不能把[3]int 传递给[4]int。长度是数组的一部分,系统认为[3]int 是一种数据类型,而[4]int 是另外一种数据类型。

(3)案例3 //默认拷贝

func modify(arr[a]int){

arr[0]= 100

fmt.Println ("modify的arr ",arr)

func main(){

var arr =[...]int[1,2,3]  //长度为3的 int 数组

modify(arr)

}

答案:编译正确。

通过三个案例,需要注意到在 go 中长度是数组类型的一部分。

相关文章
|
开发框架 .NET C#
c#数组补充
c#数组的几个简单的补充
45 0
|
编译器 Scala 开发者
函数使用注意事项和细节2|学习笔记
快速学习函数使用注意事项和细节2。
|
Go 开发者
for 循环注意事项和细节(1)| 学习笔记
快速学习 for 循环注意事项和细节(1)
for 循环注意事项和细节(1)| 学习笔记
|
Go 开发者
for 循环注意事项和细节(2)| 学习笔记
快速学习 for 循环注意事项和细节(2)
for 循环注意事项和细节(2)| 学习笔记
|
编译器 Go 开发者
包使用注意事项和细节(1)|学习笔记
快速学习包使用注意事项和细节(1)
包使用注意事项和细节(1)|学习笔记
|
存储 程序员 Go
切片注意事项和细节(2) | 学习笔记
简介:快速学习切片注意事项和细节(2)
148 0
切片注意事项和细节(2) | 学习笔记
|
Go vr&ar 开发者
切片注意事项和细节(3) | 学习笔记
简介:快速学习切片注意事项和细节(3)
切片注意事项和细节(3) | 学习笔记
|
Go 开发者
切片注意事项和细节(1) | 学习笔记
简介:快速学习切片注意事项和细节(1)
134 0
切片注意事项和细节(1) | 学习笔记