不采用数组的时候,处理问题,需要定义很多变量
func main() {
// 求3个数的平均数
n1 := 10.289
n2 := 9.98
n3 := 10.645
var total = n1 + n2 + n3
var avgNum = total / 3
_avgNum := fmt.Sprintf("%.2f", avgNum) // 保留两位小数
fmt.Println("avgNum = ", avgNum) // avgNum = 10.304666666666666
fmt.Println("_avgNum = ", _avgNum) // avgNum = 10.304666666666666
}
引入数组
介绍
使用数组修改上面的代码:
var list [3]float64
list[0] = 10.289
list[1] = 9.98
list[2] = 10.645
fmt.Printf("list 类型: %T, 值: %v \n", list, list)
var t float64
for i := 0; i < len(list); i++ {
t += list[i]
}
fmt.Println("t = ", t/3)
var avg = t / float64(len(list))
var _avg = fmt.Sprintf("%.2f", avg)
fmt.Println("_avg = ", _avg)
// list 类型: [3]float64, 值: [10.289 9.98 10.645]
// t = 10.304666666666666
// _avg = 10.30
数组内存探究
指针:
%p 表示为十六进制,并加上前导的0x
var arrInt [3]int // int占8个字节
fmt.Printf("arrInt 类型: %T, 值: %v \n", arrInt, arrInt)
fmt.Printf("arrInt 的内存地址 = %p \n", &arrInt)
for i := 0; i < len(arrInt); i++ {
fmt.Printf("list[%v]的地址是:%p, 值:%v \n", i, &arrInt[i])
}
arrInt 类型: [3]int, 值: [0 0 0] // 初始值是默认零值
arrInt 的内存地址 = 0xc000012180
list[0]的地址是:0xc000012180, 值:0
list[1]的地址是:0xc000012188, 值:0 // &list[0] + 8个字节
list[2]的地址是:0xc000012190, 值:0 // &list[1] + 8个字节
说明
计算机分配内存地址,就是首地址(数组元素首地址)
数组里面的元素的地址,是在内存中连续分配的,方便快速的读取数组中的元素,因此,只需要记录数组的首地址就可以了。
内存间隔
第二个元素的地址 = 第一个元素的地址 + 这个数组类型占用的字节数
int 类型占8个字节
int32 占4个字节
var arrInt [3]int32
fmt.Printf("arrInt 类型: %T, 值: %v \n", arrInt, arrInt)
fmt.Printf("arrInt 的内存地址 = %p \n", &arrInt)
for i := 0; i < len(arrInt); i++ {
fmt.Printf("list[%v]的地址是:%p, 值:%v \n", i, &arrInt[i])
}
arrInt 类型: [3]int32, 值: [0 0 0]
arrInt 的内存地址 = 0xc0000140a0
list[0]的地址是:0xc0000140a0, 值:0
list[1]的地址是:0xc0000140a4, 值:0 // &list[0] + 4个字节
list[2]的地址是:0xc0000140a8, 值:0 // &list[1] + 4个字节
内存图解
4种数组初始化的方式
// 初始化数组
var arr1 [3]int = [3]int{1, 2, 3}
fmt.Println("arr1 = ", arr1) // arr1 = [1 2 3]
var arr2 = [3]int{10, 20, 30}
fmt.Println("arr2 = ", arr2) // arr2 = [10 20 30]
var arr3 = [...]int{0, 1, 2}
fmt.Println("arr3 = ", arr3) // arr3 = [0 1 2]
var arr4 = [...]int{1: 100, 3: 500, 0: 11}
fmt.Println("arr4 = ", arr4) // arr4 = [11 100 0 500]
遍历数组的方式
1、常规for循环
2、for range
返回下标和元素值,类似于JavaScript种for in遍历对象,拿到的是属性和属性值
语法
for index, value := range array {
}
使用,字符串数组
var arr02 = [3]string{"luffy01", "luffy02", "luffy03"}
for index, value := range arr02 {
fmt.Println("index = ", index, "value = ", value)
}
index = 0 value = luffy01
index = 1 value = luffy02
index = 2 value = luffy03
注意事项
- 数组一旦声明/定义,长度和类型是固定的,不能修改。长度是数据类型的一部分
- 如果需要存储更多的元素,就需要先创建一个更长的数组,再把原来数组里的值复制到新数组里
- 数组元素既可以是值类型又可以是引用类型,但是不能混用(类型)。
- 数组定义之后,如果没有赋值,默认值就是对应类型的零值。
- string: “”,bool: false, int: 0
- 定义/初始化数组的时候,应该指定数组的范围。
- 数组属于值类型,在函数之间传递数组属于值拷贝,不会应该原数组
- 如若数组的长度超级大,100万个元素,传递给函数的时候,相当于复制了8M的内存空间,这种情况建议使用指针传递,只需要复制8个字节就可以,指针类型传递可以改变原数组,但是使用的时候要注意数组的数据同步问题。
func test(arr *[3]int) {
(*arr)[1] = 10
}
// main函数
// 指针数组传递
var list1 [3]int
fmt.Println("list1 = ", list1) // list1 = [0 0 0]
test(&list1)
fmt.Println("list1 = ", list1) // list1 = [0 10 0]
练习
1、byte类型的数组,长度为26,存放英文大写字母 A-Z,并输出
package main
import "fmt"
func main() {
// byte类型的数组,长度为26,存放英文大写字母 A-Z
// 字符可以参与运算: 'A' + 1 = 'B' // ascii
var myChars [26]byte
for i := 0; i < len(myChars); i++ {
myChars[i] = 'A' + byte(i)
fmt.Printf("%c ", myChars[i])
}
fmt.Println("myChars = ", myChars)
}
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
myChars = [65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90]
2、求数组最大值, 并输出对应下标
// 求最大值, 并输出对应下标
var list = [5]int{1, 0, -5, 6, 2}
var maxV int = list[0]
var maxIndex int = 0
for i := 0; i < len(list); i++ {
if maxV < list[i] {
maxV = list[i]
maxIndex = i
}
}
fmt.Println("list = ", list)
fmt.Println("maxV = ", maxV, "maxIndex = ", maxIndex)
3、求平均值
// 求平均值
var list01 [5]int = [...]int{1, -1, 20, 40, 61}
sum := 0
for _, v := range list01 {
sum += v
}
fmt.Printf("sum = %v, list01平均值:%v \n", sum, sum/len(list01))
// 平均值保留小数
fmt.Printf("sum = %v, list01平均值:%v \n", sum, float64(sum)/float64(len(list01)))
sum = 121, list01平均值:24
sum = 121, list01平均值:24.2
4、随机生成5个数,并反转打印
import “math/rand”
rand包实现了伪随机数生成器。
随机数从资源生成。包水平的函数都使用的默认的公共资源。该资源会在程序每次运行时都产生确定的序列。如果需要每次运行产生不同的序列,应使用Seed函数进行初始化。默认资源可以安全的用于多go程并发。
func (r *Rand) Intn(n int) int
返回一个取值范围在[0,n)的伪随机int值,如果n<=0会panic。
// 随机生成5个数,并反转打印
var intList [5]int
// 为了每次生成的随机数不一样,需要设置种子 Seed, 通过时间戳的方式生成种子,以保证每次都不一样
rand.Seed(time.Now().UnixNano())
for i := 0; i < len(intList); i++ {
intList[i] = rand.Intn(100)
}
fmt.Println("intList = ", intList) // intList = [81 87 47 59 81]
// 反转
// for i := len(intList) - 1; i >= 0; i-- {
// fmt.Printf("intList[%v] = %v \n", i, intList[i])
// }
fmt.Println("交换前:", intList)
var tmp int
for i := 0; i < len(intList)/2; i++ {
tmp = intList[len(intList)-1-i]
intList[len(intList)-1-i] = intList[i]
intList[i] = tmp
}
fmt.Println("交换后:", intList)
intList = [61 98 37 41 11]
交换前: [61 98 37 41 11]
交换后: [11 41 37 98 61]
// 打印值
PS D:\go-project\src\go_code\array01\main> go run .\main.go
intList = [81 87 47 59 81]
PS D:\go-project\src\go_code\array01\main> go run .\main.go
intList = [81 87 47 59 81]
PS D:\go-project\src\go_code\array01\main> go run .\main.go
intList = [82 30 76 56 10]
PS D:\go-project\src\go_code\array01\main> go run .\main.go
intList = [24 95 48 15 19]
PS D:\go-project\src\go_code\array01\main>