数组,可以存放多个相同类型数据的一种特殊的数据类型

一、基本语法及案例演示

语法格式

var  变量名称  [空间大小]数据类型



//我们在创建数组的时候会指定这个数据的空间有多大
//如:
//var hens [6]float64
//定义一个hens的数组, 空间大小位6,允许存放6个float64的值

案例

假设有一个养鸡场有6只鸡,他们的体重分别是 3kg,5kg,1kg,3.4kg,2kg,50kg
 那这6只鸡 的总体重是多少?平均体重是多少?

package main

import (
	"fmt"
)


func main(){

	var hens [6]float64 //定义一个数组,空间大小为6


	hens[0] = 3.0  //和其他语法的列表相似,hens[索引位],空间大小是6
	hens[1] = 5.0  //索引位是0-5
	hens[2] = 1.0
	hens[3] = 3.4
	hens[4] = 2.0
	hens[5] = 50.0


	totalWeight2 := 0.0     //定义变量接收总体重

	for i := 0; i < len(hens); i++ {  //循环遍历 将所有体重相加
		totalWeight2 += hens[i]
	}


	avgWeight2 := fmt.Sprintf("%.2f", totalWeight2 / len(hens))  
                       //fmt.Sprintf 将计算的值接收
                       //"%.2f"中的2表示精度 保留小数点后两位
                       //len 获取数组的长度

	fmt.Printf("totalWeight2=%v avgWeight2=%v",totalWeight2, avgWeight2)
}

1、 数组的默认值

和前面所有的数据类型一样,数组定义后也是有默认值的,数组内数据的默认值取决于值的类型

package main
import (
	"fmt"
)

func main() {
	var intArr [3]int  //比如这里是一个int的数组,int类型变量的默认值是0

	fmt.Println(intArr)
}

返回

[0 0 0]

 2、 数组的地址可以通过数组名来获取

package main
import (
	"fmt"
)

func main() {
	var intArr [3]int
	
	fmt.Printf("intArr的内存地址=%p",&intArr)  //也是通过& 来获取内存地址
}

返回

intArr的内存地址=0xc000016120

3、数组的第一个元素的地址,就是数组的首地址

package main
import (
	"fmt"
)

func main() {
	var intArr [3]int
	
	fmt.Printf("%p\n%p\n%p\n%p\n",
		&intArr,
		&intArr[0],
		&intArr[1],
		&intArr[2])

}

返回

0xc000016120
0xc000016120
0xc000016128
0xc000016130

说明

1、通过上面结果可知,数组的内存地址是连续性的
2、intArr数组名 和intArr[0] 第一个索引位的地址是一样的,也证明了数组的第一个元素的地址,就是数组的首地址
3 intArr[0] 到intArr[1]顺延的内存地址,就是在数组定义时所指定的数据类型(int)的大小(字节数)的值

int类型占用8个字节,通过上面的接结果可知:
    
0xc000016120
0xc000016120  //索引位0  和数组地址相同
0xc000016128  //索引位1  基于0顺延一个int类型的8字节
0xc000016130  //索引位2  基于1顺延一个int的字节,
              //因为这里是16进制,所以结果是30

4、改变数组中的值是不会修改内存地址的

package main
import (
	"fmt"
)

func main() {
	var intArr [3]int
	intArr[0] = 10
	intArr[1] = 20
	intArr[2] = 30
	fmt.Println(intArr)
	fmt.Printf("%p\n%p\n%p\n%p\n",
		&intArr,
		&intArr[0],
		&intArr[1],
		&intArr[2])

	intArr[0] = 40
	intArr[1] = 50
	intArr[2] = 60
	fmt.Println(intArr)
	fmt.Printf("%p\n%p\n%p\n%p\n",
		&intArr,
		&intArr[0],
		&intArr[1],
		&intArr[2])

}

返回

[10 20 30]
0xc000016120
0xc000016120
0xc000016128
0xc000016130

[40 50 60]
0xc000016120
0xc000016120
0xc000016128
0xc000016130

5、从终端接收数值存储到数组中


package main
import (
	"fmt"
)

func main() {
	var score [5]float64

	for i := 0; i < len(score); i++{
		fmt.Printf("请输入第%d个元素的值",i+1)
		fmt.Scanln(&score[i])    //Scanln接收用户输入
	}

	fmt.Println(score)      //输出整个数组的值

	for i := 0; i < len(score); i++{
		fmt.Printf("score[%d]=%v\n",i,score[i])  //%d 表示十进制显示,%v表示直接输出
	}
}

返回

请输入第1个元素的值1
请输入第2个元素的值2
请输入第3个元素的值3
请输入第4个元素的值4
请输入第5个元素的值5
[1 2 3 4 5]
score[0]=1
score[1]=2
score[2]=3
score[3]=4
score[4]=5

二、四种初始化数组的方法

1、在定义时直接初始化

package main

import (
	"fmt"
)

func main()  {
	var numArr01 [3]int = [3]int{1, 2, 3} //在声明数组的时候直接赋值
	fmt.Println("numArr01",numArr01)
}

//numArr01 [1 2 3]

2、可以不定义数组类型,go有自己的类型推导自动识别

package main

import (
	"fmt"
)

func main()  {
	var numArr02 = [3]int{1, 2, 3}
	fmt.Println("numArr02",numArr02)
}

3、不设置数组的大小,自动识别元素的数量

package main

import (
	"fmt"
)

func main()  {
	var numArr03 = [...]int{1, 2, 3}  //...表示自动识别
	fmt.Println("numArr03",numArr03)
}

4、给指定索引位添加元素

package main

import (
	"fmt"
)

func main()  {
	//这里的1、0、2表示数组内的索引位
	//这里是给指定的元素初始化值
	var numArr04 = [...]int{1: 800, 0: 900, 2:999}
	fmt.Println("numArr04",numArr04)


	//类型推导也可以
	numArr05 := [...]int{1: 800, 0: 900, 2:999}
	fmt.Println("numArr05",numArr05)
}

//numArr04 [900 800 999]
//numArr05 [900 800 999]

三、遍历数组(for-range)

//格式
for index, value := range 数组列表 {
   代码块
}


说明:
  //index是数组循环获取的的下标,从0开始
  //value"是数组循环获取的对应索引下标的值
  //他们都是仅在for循环内部可见的局部变量
  //遍历数组元素时,如果不需要使用下标index,可以直接把下班index标为下划线"_"
  //index 和value名称不是固定的,可以自定义,一般命名为index和value

案例1 基本使用

package main
import (
	"fmt"
)

func main() {

	heroes := [...]string{"宋江","无用","卢俊义"}

	for index, value := range heroes {

		fmt.Printf("index=%v value=%v\n",index,value)  //遍历输出索引位和对应的值
	}
}

返回

index=0 value=宋江
index=1 value=无用
index=2 value=卢俊义

案例2  除去下标

package main
import (
	"fmt"
)

func main() {
	heroes := [...]string{"宋江","无用","卢俊义"}

	for _, value := range heroes {
		//如果不需要索引位的值,修改为下划线"_"即可
		//将index改为下划线
		//直接输入value就可以取值
		fmt.Printf("value=%v\n",value)
	}
}

返回

value=宋江
value=无用
value=卢俊义

四、数组使用细节和注意事项

1、数组不能动态变化

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

 案例

package main
import (
	"fmt"
)

func main() {
	var arr01 [3]int
	arr01[0] = 1
	arr01[1] = 30
	arr01[2] = 1.1  //这里会报错,因为数组类型是int,而1.1是浮点值
	arr01[3] = 890 //无效的 数组 索引 '3' (3 元素的数组超出界限)
	               //长度固定,不能动态变化,
}

2、设置数组时,如果不设置空间大小则视为切片

var arr []int    //切片是啥后面再说

3、数组的类型可以是所有类型

数组中元素可以是任何类型,包括值类型和引用类型,但是不能混用

4、数组创建后,有默认值

数值类型数组   //0
字符串数组     //""
bool数组      //false

//等同于基本数据类型本身

案例

package main
import (
	"fmt"
)

func main() {
	//整数、浮点数、默认都为0
	//字符串  默认 ""
	//bool类型  默认是false
	var arr01 [3]int
	var arr02 [3]string
	var arr03 [3]bool
	fmt.Printf("arr01=%v\narr02=%v\narr03=%v\n",arr01,arr02,arr03)
}

返回

arr01=[0 0 0]
arr02=[  ]
arr03=[false false false]

5、 使用数组的步骤

1. 声明数组并开辟内存空间      //make和new
2. 给数组元素赋值(默认0值)

案例  new 和make的区别

6、数组的下标是从0开始的

package main
import (
	"fmt"
)

func main() {
  
  var arr04 [3]string //数组的下标是从0开始的  0-2
  varr04[3] = "tom"   //当索引位超出会报越界
}

7、go 的数组是值类型

package main
import (
	"fmt"
)

func test01(arr [3]int){
	arr[0] = 88   //值转递,相当于是将main的arr数组拷贝了一份
	              //所以在这里被修改后是不会影响到main中调用的数组的
}



func main() {
	arr := [3]int{11,22,33}

	test01(arr)    //将数组作为参数传递
	fmt.Println(arr)
}

返回

[11 22 33]

8、修改其他函数的数组

上面我们已经知道了数组是以值拷贝的形式进行传参的,但是我们想要其他函数中修改数组的值怎么做?  使用指针

案例

package main

import (
	"fmt"
)


func test01(arr *[3]int){   //*开头表示 我这边是以指针的形式接收数据的
	//引用指针,相当于直接调用main中arr变量的内存地址来修改数据
	(*arr)[0] = 88    //在赋值时,我们去调用这个指针变量
	                  //*arr去调用,但同时这是一个数组类型,所以要加括号
}


func main() {
	arr := [3]int{11,22,33}

	test01(&arr)   //我们传参的时候将数组的内存地址进行传递
	fmt.Println(arr)
}

返回

[88 22 33]

9、数组长度是数组类型的一部分

在传递函数参数时,需要考虑数组的长度. 判断以下三段代码是否正确

案例1  

package main
import (
	"fmt"
)

func modify(arr []int){   //这里接收参数时没有设置数组的长度,说明接收的就变成了切片
                          //正确的写法是arr [3]int
	arr[0] = 100
	fmt.Println("modify 的arr",arr)
}

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

案例2

package main
import (
	"fmt"
)

func modify(arr [4]int){  //arr [4]int 和下面数组的长度不同
	                      //下面的数组只有3位的长度,不能传递到4长度的数组
	                      //不同长度的数组相当于是不同的数据类型
	arr[0] = 100
	fmt.Println("modify 的arr",arr)
}

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

案例3

package main
import (
	"fmt"
)

func modify(arr [3]int){
	arr[0] = 100
	fmt.Println("modify 的arr",arr)
}

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

//正确