当前位置:   article > 正文

Golang学习(十四)数组_golang 数组

golang 数组

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

一、基本语法及案例演示

语法格式

  1. var 变量名称 [空间大小]数据类型
  2. //我们在创建数组的时候会指定这个数据的空间有多大
  3. //如:
  4. //var hens [6]float64
  5. //定义一个hens的数组, 空间大小位6,允许存放6个float64的值

案例

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

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main(){
  6. var hens [6]float64 //定义一个数组,空间大小为6
  7. hens[0] = 3.0 //和其他语法的列表相似,hens[索引位],空间大小是6
  8. hens[1] = 5.0 //索引位是0-5
  9. hens[2] = 1.0
  10. hens[3] = 3.4
  11. hens[4] = 2.0
  12. hens[5] = 50.0
  13. totalWeight2 := 0.0 //定义变量接收总体重
  14. for i := 0; i < len(hens); i++ { //循环遍历 将所有体重相加
  15. totalWeight2 += hens[i]
  16. }
  17. avgWeight2 := fmt.Sprintf("%.2f", totalWeight2 / len(hens))
  18. //fmt.Sprintf 将计算的值接收
  19. //"%.2f"中的2表示精度 保留小数点后两位
  20. //len 获取数组的长度
  21. fmt.Printf("totalWeight2=%v avgWeight2=%v",totalWeight2, avgWeight2)
  22. }

1、 数组的默认值

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

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. var intArr [3]int //比如这里是一个int的数组,int类型变量的默认值是0
  7. fmt.Println(intArr)
  8. }

返回

[0 0 0]

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

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. var intArr [3]int
  7. fmt.Printf("intArr的内存地址=%p",&intArr) //也是通过& 来获取内存地址
  8. }

返回

intArr的内存地址=0xc000016120

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

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. var intArr [3]int
  7. fmt.Printf("%p\n%p\n%p\n%p\n",
  8. &intArr,
  9. &intArr[0],
  10. &intArr[1],
  11. &intArr[2])
  12. }

返回

  1. 0xc000016120
  2. 0xc000016120
  3. 0xc000016128
  4. 0xc000016130

说明

  1. 1、通过上面结果可知,数组的内存地址是连续性的
  2. 2、intArr数组名 和intArr[0] 第一个索引位的地址是一样的,也证明了数组的第一个元素的地址,就是数组的首地址
  3. 3 intArr[0] 到intArr[1]顺延的内存地址,就是在数组定义时所指定的数据类型(int)的大小(字节数)的值
  4. int类型占用8个字节,通过上面的接结果可知:
  5. 0xc000016120
  6. 0xc000016120 //索引位0 和数组地址相同
  7. 0xc000016128 //索引位1 基于0顺延一个int类型的8字节
  8. 0xc000016130 //索引位2 基于1顺延一个int的字节,
  9. //因为这里是16进制,所以结果是30

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

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. var intArr [3]int
  7. intArr[0] = 10
  8. intArr[1] = 20
  9. intArr[2] = 30
  10. fmt.Println(intArr)
  11. fmt.Printf("%p\n%p\n%p\n%p\n",
  12. &intArr,
  13. &intArr[0],
  14. &intArr[1],
  15. &intArr[2])
  16. intArr[0] = 40
  17. intArr[1] = 50
  18. intArr[2] = 60
  19. fmt.Println(intArr)
  20. fmt.Printf("%p\n%p\n%p\n%p\n",
  21. &intArr,
  22. &intArr[0],
  23. &intArr[1],
  24. &intArr[2])
  25. }

返回

  1. [10 20 30]
  2. 0xc000016120
  3. 0xc000016120
  4. 0xc000016128
  5. 0xc000016130
  6. [40 50 60]
  7. 0xc000016120
  8. 0xc000016120
  9. 0xc000016128
  10. 0xc000016130

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

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. var score [5]float64
  7. for i := 0; i < len(score); i++{
  8. fmt.Printf("请输入第%d个元素的值",i+1)
  9. fmt.Scanln(&score[i]) //Scanln接收用户输入
  10. }
  11. fmt.Println(score) //输出整个数组的值
  12. for i := 0; i < len(score); i++{
  13. fmt.Printf("score[%d]=%v\n",i,score[i]) //%d 表示十进制显示,%v表示直接输出
  14. }
  15. }

返回

  1. 请输入第1个元素的值1
  2. 请输入第2个元素的值2
  3. 请输入第3个元素的值3
  4. 请输入第4个元素的值4
  5. 请输入第5个元素的值5
  6. [1 2 3 4 5]
  7. score[0]=1
  8. score[1]=2
  9. score[2]=3
  10. score[3]=4
  11. score[4]=5

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

1、在定义时直接初始化

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

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

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. var numArr02 = [3]int{1, 2, 3}
  7. fmt.Println("numArr02",numArr02)
  8. }

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

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. var numArr03 = [...]int{1, 2, 3} //...表示自动识别
  7. fmt.Println("numArr03",numArr03)
  8. }

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

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. //这里的1、0、2表示数组内的索引位
  7. //这里是给指定的元素初始化值
  8. var numArr04 = [...]int{1: 800, 0: 900, 2:999}
  9. fmt.Println("numArr04",numArr04)
  10. //类型推导也可以
  11. numArr05 := [...]int{1: 800, 0: 900, 2:999}
  12. fmt.Println("numArr05",numArr05)
  13. }
  14. //numArr04 [900 800 999]
  15. //numArr05 [900 800 999]

三、遍历数组(for-range)

  1. //格式
  2. for index, value := range 数组列表 {
  3. 代码块
  4. }
  5. 说明:
  6. //index是数组循环获取的的下标,从0开始
  7. //value"是数组循环获取的对应索引下标的值
  8. //他们都是仅在for循环内部可见的局部变量
  9. //遍历数组元素时,如果不需要使用下标index,可以直接把下班index标为下划线"_"
  10. //index 和value名称不是固定的,可以自定义,一般命名为index和value

案例1 基本使用

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. heroes := [...]string{"宋江","无用","卢俊义"}
  7. for index, value := range heroes {
  8. fmt.Printf("index=%v value=%v\n",index,value) //遍历输出索引位和对应的值
  9. }
  10. }

返回

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

案例2  除去下标

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. heroes := [...]string{"宋江","无用","卢俊义"}
  7. for _, value := range heroes {
  8. //如果不需要索引位的值,修改为下划线"_"即可
  9. //将index改为下划线
  10. //直接输入value就可以取值
  11. fmt.Printf("value=%v\n",value)
  12. }
  13. }

返回

  1. value=宋江
  2. value=无用
  3. value=卢俊义

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

1、数组不能动态变化

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

 案例

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

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

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

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

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

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

  1. 数值类型数组 //0
  2. 字符串数组 //""
  3. bool数组 //false
  4. //等同于基本数据类型本身

案例

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. //整数、浮点数、默认都为0
  7. //字符串 默认 ""
  8. //bool类型 默认是false
  9. var arr01 [3]int
  10. var arr02 [3]string
  11. var arr03 [3]bool
  12. fmt.Printf("arr01=%v\narr02=%v\narr03=%v\n",arr01,arr02,arr03)
  13. }

返回

  1. arr01=[0 0 0]
  2. arr02=[ ]
  3. arr03=[false false false]

5、 使用数组的步骤

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

案例  new 和make的区别

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

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. var arr04 [3]string //数组的下标是从0开始的 0-2
  7. varr04[3] = "tom" //当索引位超出会报越界
  8. }

7、go 的数组是值类型

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func test01(arr [3]int){
  6. arr[0] = 88 //值转递,相当于是将main的arr数组拷贝了一份
  7. //所以在这里被修改后是不会影响到main中调用的数组的
  8. }
  9. func main() {
  10. arr := [3]int{11,22,33}
  11. test01(arr) //将数组作为参数传递
  12. fmt.Println(arr)
  13. }

返回

[11 22 33]

8、修改其他函数的数组

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

案例

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func test01(arr *[3]int){ //*开头表示 我这边是以指针的形式接收数据的
  6. //引用指针,相当于直接调用main中arr变量的内存地址来修改数据
  7. (*arr)[0] = 88 //在赋值时,我们去调用这个指针变量
  8. //*arr去调用,但同时这是一个数组类型,所以要加括号
  9. }
  10. func main() {
  11. arr := [3]int{11,22,33}
  12. test01(&arr) //我们传参的时候将数组的内存地址进行传递
  13. fmt.Println(arr)
  14. }

返回

[88 22 33]

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

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

案例1  

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func modify(arr []int){ //这里接收参数时没有设置数组的长度,说明接收的就变成了切片
  6. //正确的写法是arr [3]int
  7. arr[0] = 100
  8. fmt.Println("modify 的arr",arr)
  9. }
  10. func main(){
  11. var arr = [...]int{1,2,3}
  12. modify(arr)
  13. }

案例2

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func modify(arr [4]int){ //arr [4]int 和下面数组的长度不同
  6. //下面的数组只有3位的长度,不能传递到4长度的数组
  7. //不同长度的数组相当于是不同的数据类型
  8. arr[0] = 100
  9. fmt.Println("modify 的arr",arr)
  10. }
  11. func main(){
  12. var arr = [...]int{1,2,3}
  13. modify(arr)
  14. }

案例3

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func modify(arr [3]int){
  6. arr[0] = 100
  7. fmt.Println("modify 的arr",arr)
  8. }
  9. func main(){
  10. var arr = [...]int{1,2,3}
  11. modify(arr)
  12. }
  13. //正确

数组练习题

1、创建一个byte类型的26个元素的数组

创建一个byte类型的26个元素的数组,分别放置'A'-'Z'    ,使用for循环访问所有元素并打印出来。

提示:

     字符类型(byte)运算 'A'+ 1 -->'B'    这里的1也是byte类型才可以。  然后通过printf  %c输出字符

  1. package main
  2. import "fmt"
  3. func main(){
  4. var shuzu [26]byte
  5. for key,_ := range shuzu{ //for-range遍历数组
  6. shuzu[key] = 'A' + byte(key) //'A'加索引位的byte作为值赋予
  7. }
  8. fmt.Printf("%c ",shuzu) //以字符形式输出
  9. }

返回

[A B C D E F G H I J K L M N O P Q R S T U V W X Y Z] 

练习2  请求出一个数组的最大值,并得到对应的下标

  1. /*
  2. 1. 声明一个数组 var intArr[5] = [...]int {1,-1,9,90,11}
  3. 2. 假定第一个元素就是最大值,下标就是0
  4. 3. 然后从第二个元素开始循环比较,如果发现有更大的,则交换
  5. */
  6. package main
  7. import "fmt"
  8. func main(){
  9. var test = [5]int{12,2,21,45,5}
  10. maxzhi := test[0]
  11. xiabiao := 0
  12. //这里len去获取这个数组的长度,然后循环每次去判断是否小于这个长度
  13. //这里因为要从索引位1开始,1-4的位置,总长度是5,所以必须是小于,不能是小于等于,不然长度不够了
  14. for i := 1; i < len(test);i++{
  15. if maxzhi < test[i]{
  16. maxzhi = test[i]
  17. xiabiao = i
  18. }
  19. }
  20. fmt.Println("最大值",maxzhi)
  21. fmt.Println("最大值下标",xiabiao)
  22. }

练习3  请求出一个数组的和 与他的平均值 for-range

  1. /*
  2. 请求出一个数组和 和平均值 for-range
  3. 思路
  4. 1. 就是声明一个数组
  5. 2. 求出和sum
  6. 3. 求出平均值
  7. */
  8. package main
  9. import (
  10. "fmt"
  11. )
  12. func main(){
  13. var intArr2 = [...]int {1,2,3,4,7}
  14. sum := 0
  15. for _, val := range intArr2 {
  16. //_下划线 val,表示只要值,不要索引下标
  17. sum += val
  18. }
  19. fmt.Printf("sum=%v 平均值=%v\n", sum, sum / len(intArr2))
  20. //上面显示的是sum=17 平均值=3
  21. //这里应该是有小数点的,但是因为int的缘故都抹掉了
  22. //所以我们需要修改一下平均值的数据类型和除的个数的数据类型
  23. fmt.Printf("sum=%v 平均值=%v", float64(sum), float64(sum) / float64(len(intArr2)))
  24. }

 

数组的复杂使用反转

随机生成5个数,并将其反转输出

案例

  1. /*
  2. 思路
  3. 1. 随机生成5个数,rand Intn()函数
  4. 2. 当我们得到随机数后,就放入到一个数组中
  5. 3. 反转打印,交换的次数
  6. 第一个和倒数第一个元素交换,第二个和倒数第二个交换
  7. 如下
  8. [1 2 3 4 5] 反转为 [5 4 3 2 1 ]
  9. 或者说
  10. [1 2 3 4 5 6 ] 反转为 [ 6 5 4 3 2 1]
  11. 他反转的概念可以理解为如下
  12. [1 5]
  13. [ 2 4]
  14. [3]
  15. 我们是从两边开始替换,然后向中间靠拢的
  16. */
  17. package main
  18. import (
  19. "fmt"
  20. "math/rand"
  21. )
  22. func main(){
  23. var intArr3 [5]int
  24. for i := 0; i < len(intArr3); i++{
  25. intArr3[i] = rand.Intn(100) //随机生成0-100的整数
  26. }
  27. fmt.Println("我是交换之前的值",intArr3)
  28. temp :=0
  29. for i := 0; i < len(intArr3) / 2; i++{
  30. //考虑到要进行反转,需要先筛选出一半的值存下来 比如 1 2
  31. //然后拿另一半的值,覆盖之前取出值的位置 4 5 --》 1 2
  32. //最后再将之前取出的值写入到之后取出值的位置 1 2 --> 4 5
  33. //以此来完成前后值的反转
  34. temp = intArr3[len(intArr3) - 1 - i]
  35. //len(intArr3) - 1 来获取真正的索引位, (len的值是统计长度,是从1开始的,所以要减一)
  36. //第一次循环,数组会拿到索引总长度-i的值,也就是0-4的最大值4位置的值
  37. //将最后的索引位值 放入到临时变量中
  38. intArr3[len(intArr3) - 1 - i ] = intArr3[i]
  39. //然后将数组中第一个值写入到数组中最大值4的位置
  40. intArr3[i] = temp
  41. //最后将之前拿到的最后一位索引位的值,再赋予到第一位的值的索引位,完成反转
  42. }
  43. fmt.Println("我是交换之后的值",intArr3)
  44. }

返回

  1. 我是交换之前的值 [81 87 47 59 81]
  2. 我是交换之后的值 [81 59 47 87 81]

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/206337
推荐阅读
相关标签
  

闽ICP备14008679号