开发者学堂课程【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
v
ar index int = 3
//在运行的时候会直接报错,显示越界
a
rr04[3] = “tom”
//如果直接访问3,则会报错,因为下标是0-2,因此arr04[3]就越界
注意:在编程的时候如果发现有越界的错误,肯定是程序中某一个变量的值超过了它能够访问的下标范围
运行结果如下:
可以发现在第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
a
rr:=[3]int{11,22,33}
t
est01(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 栈中的数组没有任何影响。
输出效果如下:
(3)如想在其它函数中,去修改原来的数组,可以使用引用传递(指针方式)
//默认虽然为值传递,但是如果我们引用指针方式传递,也可以成功
如何让数组改变默认传递方式:
(4)案例:
//函数
func test02(arr *[3]int) { //添加一个*后,arr就变成了一个指向数组的指针
//fmt.Printf(“arr指针的地址=%p”,arr) //指针本身有一个地址,可以将其打印出来
//不可以使用以前的方法直接访问数组,需要先将arr的取值符取到,然后再取第一个元素
(*arr)[0] = 88 //!!重要
}
a
rr :=[3]int{11,22,33}
f
mt.Printf(“arr
的地址=
%p”,&arr)
//打印数组的首地址
t
est02(&arr)
//将数组的首地址传递给上方的 arr 指针
f
mt.Println(“main arr=”,arr)
}
运行结果如下:
可以发现输出的内容发生了变化,第一个值变成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
输出结果如下:
可以看到 arr 指针的地址是0xc042004030,也就是说指针本身拥有一个地址。arr是一个指针,它有一个空间存放的是指向原先数组的首地址,同时它本身存放地址的空间也有一个地址。
//通过指针传递的效率高,因为在拷贝的时候只是拷贝的变量的副本(地址),地址的数据量小,而上方是进行的值拷贝,如果是一个庞大的值,则非常耗费资源。
//在使用数组时如果想改变外部的数组,就使用指针传递,效果高而且速度快
9.长度是数组类型的一部分,在传递函数参数时需要考虑数组的长度。
(1)案例1:
//默认值拷贝
func modify(arr[]int ){
//接收时,arr[]中没有数值
arr[0]= 100
f
m
t.Println("modify的arr ",arr)
}
func main(){
//定义一个数组
var arr =[…]int[1,2,3]
//数组的长度为3
modif
y
(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 中长度是数组类型的一部分。