作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
一.数组的定义
1.数组的引入
package main
import "fmt"
func main() {
// 实现的功能,将西游记师徒四人的分数求和,平均数
tangsanzang := 100
sunwukong := 99
zhubajie := 88
shaheshang := 77
// 求和
sum := tangsanzang + sunwukong + zhubajie + shaheshang
// 求平均数
avg := sum / 4
fmt.Printf("西游记师徒四人的总分: %d, 平均成绩: %d\n", sum, avg)
// 上述代码有个缺点,分数变量个数定义太多,不利于项目维护。
}
2.数组的概述
数组(array)是同一种数据类型元素的集合,其有以下3个特点:
- 1.长度固定;
- 2.连续内存空间;
- 3.同一类型集合;
在Go语言中,数组从声明时就确定,使用时可以修改数组成员,但是数组大小不可变化。
定义数组的语法:
var 数组变量名 [元素数量]T
温馨提示:
数组的长度必须是常量,并且长度是数组类型的一部分。一旦定义,长度不能变。
3.数组案例
package main
import "fmt"
func main() {
// 定义一个长度为4的数组
var xiyouji [4]int
// 使用一个变量就可以进行存储
xiyouji[0] = 100
xiyouji[1] = 99
xiyouji[2] = 88
xiyouji[3] = 77
// 求和
sum := 0
for i := 0; i < len(xiyouji); i++ {
sum += xiyouji[i]
}
// 求平均数
avg := sum / len(xiyouji)
fmt.Printf("成绩的总和: %v, 成绩的平均数: %v\n", sum, avg)
}
4.数组的内存分析
package main
import "fmt"
func main() {
// 声明长度为5的数组
var array [5]uint16
// 数组赋值
array[0] = 100
array[1] = 200
array[2] = 300
// 获取数组的长度
fmt.Printf("数组长度为:%d,数组的内容:%v\n", len(array), array)
// 数组中存储的地址
fmt.Printf("数组的地址:%p\n", &array)
// 第一个空间的地址
fmt.Printf("数组的第一个地址:%p\n", &array[0])
// 第二个空间的地址
fmt.Printf("数组的第二个地址:%p\n", &array[1])
// 第三个空间的地址
fmt.Printf("数组的第三个地址:%p\n", &array[2])
// 第四个空间的地址
fmt.Printf("数组的第二个地址:%p\n", &array[3])
// 第五个空间的地址
fmt.Printf("数组的第三个地址:%p\n", &array[4])
}
5.四种数组初始化的方式
package main
import "fmt"
func main() {
var (
// 第一种: 带数组类型初始化列表
array01 [7]string = [7]string{"北京", "上海", "深圳", "西安", "成都", "杭州", "乌兰察布"}
// 第二种: 不带数组类型初始化列表
array02 = [4]bool{false, true, true}
// 第三种: 自行推断长度
array03 = [...]uint8{11, 22, 33, 44, 55}
// 第四种: 指定索引值
array04 = [...]int{1: 100, 3: -200, 5: 300}
)
fmt.Printf("array01类型: %T,值: %v, 长度: %d\n", array01, array01, len(array01))
fmt.Printf("array02类型: %T,值: %v, 长度: %d\n", array02, array02, len(array02))
fmt.Printf("array03类型: %T,值: %v, 长度: %d\n", array03, array03, len(array03))
fmt.Printf("array04类型: %T,值: %v, 长度: %d\n", array04, array04, len(array04))
}
二.数组的遍历
1.数组遍历的方式
数组的遍历方式有两种,即普通for循环和键值循环。
键值循环(for range)是GO语言特有的一种迭代结构,在许多情况下都非常有用,for range看了眼遍历数组,切片,字符串,map即通道。
for range语法上类似于其他语言中的foreach语句,一般形式如下:
for key,value := range 数组标识符 {
...
}
温馨提示:
1.数组标识符就是你定义的数组变量;
2.每次遍历得到的索引用key接收,每次遍历得到的索引位置上的值用value接收;
3.key,value的名称是随便起名,比如可以写成类似: "k,v"等;
4.key,value属于局部变量,每次变量都被修改了数据;
5.key,value的值如何你想忽略的话,接受的时候使用"_"代替即可;
2.for循环遍历
package main
import "fmt"
func main() {
// 功能实现: 手动录入3个学生的分数,然后打印出来。
var scores [3]int
// 将分数存储在数组中:
for i := 0; i < len(scores); i++ {
fmt.Printf("请录入第[%d]个学生的成绩: ", i+1)
fmt.Scanln(&scores[i])
}
// 使用for循环展示分数
for i := 0; i < len(scores); i++ {
fmt.Printf("第[%d]个学生的成绩为: %d\n", i+1, scores[i])
}
}
3.for range遍历
package main
import "fmt"
func main() {
// 功能实现: 手动录入3个学生的分数,然后打印出来。
var scores [3]int
// 将分数存储在数组中:
for i := 0; i < len(scores); i++ {
fmt.Printf("请录入第[%d]个学生的成绩: ", i+1)
fmt.Scanln(&scores[i])
}
// 使用for-range循环展示分数
for index, value := range scores {
fmt.Printf("第[%d]个学生的成绩为: %d\n", index+1, value)
}
}
三.数组的注意事项
1.数组长度属于类型的一部分
package main
import "fmt"
func main() {
var (
// 数组长度属于类型的一部分
array01 = [3]int{3, 5, 7}
array02 = [5]int{11, 22, 33, 44, 55}
)
fmt.Printf("array01数组的类型为: %T,数据为: %v\n", array01, array01)
fmt.Printf("array02数组的类型为: %T,数据为: %v\n", array02, array02)
}
2.数组属于值类型,默认进行值传递
package main
import "fmt"
func setName(name [3]string) {
name[0] = "JasonYin"
fmt.Printf("in setName ... name = %v\n", name)
}
func main() {
/*
数组是值类型,赋值和传参会复制整个数组。因此改变副本的值,不会改变本身的值。
温馨提示:
(1)数组支持"=="、"!="操作符,因为内存总是被初始化过的;
(2)"[n]*T"表示指针数组,"*[n]T"表示数组指针;
*/
var names = [3]string{"尹正杰", "yinzhengjie", "jasonyin2020"}
fmt.Printf("调用setName前: in main ... names = %v\n", names)
// 调用setName函数时,传递的数组属于值传递,因此setName内的修改并不会影响到main函数的数组
setName(names)
fmt.Printf("调用setName后: in main ... names = %v\n", names)
}
3.数组实现引用传递
package main
import "fmt"
// 接受的形参类型变为指针类型
func setName(name *[3]string) {
// 取出指针的地址存储的数组地址,基于数组的内存地址修改数据
(*name)[0] = "JasonYin"
fmt.Printf("in setName ... name = %v,地址: %p\n", name, name)
}
func main() {
var names = [3]string{"尹正杰", "yinzhengjie", "jasonyin2020"}
fmt.Printf("调用setName前: in main ... names = %v,地址: %p\n", names, &names)
// 传入names数组的地址
setName(&names)
fmt.Printf("调用setName后: in main ... names = %v,地址: %p\n", names, &names)
}
四.多维数组
1.字符串二维数组案例
package main
import (
"fmt"
)
func main() {
// 定义二维数组,如果有元素默认进行初始化赋值,则有默认值("零值")
address := [5][2]string{
{"陕西省", "西安市"},
{"河北省", "石家庄市"},
{"黑龙江省", "哈尔滨"},
{"江苏省", "南京市"},
}
fmt.Println(address)
// 支持索引取值
fmt.Println(address[2][1])
}
2.二维数组的内存分析
package main
import "fmt"
func main() {
// 定义二维数组,有默认的初始值
var array [2][3]uint16
// 二维数组赋值
array[0][0] = 100
array[0][1] = 200
array[1][1] = 300
fmt.Printf("array地址: %p\n", &array)
fmt.Printf("array[0]地址: %p\n", &array[0])
fmt.Printf("array[0][0]地址: %p\n", &array[0][0])
fmt.Printf("array[1]地址: %p\n", &array[1])
fmt.Printf("array[1][0]地址: %p\n", &array[1][0])
fmt.Printf("array[1][2]地址: %p\n", &array[1][2])
}
3.二维数组的三种数组初始化的方式
package main
import "fmt"
func main() {
var (
// 第一种: 带数组类型初始化列表
array01 [5][2]string = [5][2]string{
{"陕西省", "西安市"},
{"河北省", "石家庄市"},
{"黑龙江省", "哈尔滨"},
{"江苏省", "南京市"},
}
// 第二种: 不带数组类型初始化列表
array02 = [4][2]bool{
{true, false},
{true, true},
{false, false},
}
// 第三种: 自行推断长度,多维数组只有第一层可以使用"..."来让编译器推导数组长度。
array03 = [...][3]uint8{
{1, 4, 7},
{2, 5, 8},
{3, 6, 9},
{11, 22, 33},
{44, 55, 66},
{77, 88, 99},
}
// 不支持多维数组的内层使用"...",会编译报错: "invalid use of [...] array (outside a composite literal)"
// array03 = [3][...]uint8{
// {11, 22, 33},
// {44, 55, 66},
// {77, 88, 99},
// }
)
fmt.Printf("array01类型: %T,值: %v, 长度: %d\n", array01, array01, len(array01))
fmt.Printf("array02类型: %T,值: %v, 长度: %d\n", array02, array02, len(array02))
fmt.Printf("array03类型: %T,值: %v, 长度: %d\n", array03, array03, len(array03))
}
五.二维数组的遍历
1.基于for循环遍历
package main
import "fmt"
func main() {
// 定义二维数组
var city = [...][3]string{
{"西安", "安康", "渭南"},
{"石家庄", "邯郸", "保定"},
{"郑州", "洛阳", "南阳"},
}
// 通过for循环遍历
for i := 0; i < len(city); i++ {
for j := 0; j < len(city[i]); j++ {
fmt.Print(city[i][j], "\t")
}
fmt.Println()
}
}
2.for range遍历
package main
import "fmt"
func main() {
// 定义二维数组
var province = [...][3]string{
{"西安", "安康", "渭南"},
{"石家庄", "邯郸", "保定"},
{"郑州", "洛阳", "南阳"},
}
// 通过for-range循环遍历
for index, city := range province {
for key, value := range city {
fmt.Printf("province[%d][%v] = %v\t\t", index, key, value)
}
fmt.Println()
}
}
六.练习题
1.将10以内的奇数放在同一个数组中并求和
package main
import (
"fmt"
)
func main() {
// 题意: 将10以内的奇数放在同一个数组中并求和
numberList := [5]int{1, 3, 5, 7, 9}
var sum int
for _, v := range numberList {
sum += v
}
fmt.Println(sum)
}
2.找出数组中和为指定值的两个元素的下标
package main
import (
"fmt"
)
func main() {
// 找出数组中和为指定值的两个元素的下标,从数组[1,3,5,7,8]中找出和为8的两个元素元素的下标。
// 需求分析:
// (1)一次取出每个元素;
// (2)计算一下: other = 8 - 当前值;
// (3)上一步计算出other的值后再和现有数组的元素进行比较,若存在就打印出来
numberList := [5]int{1, 3, 5, 7, 8}
for k1, v1 := range numberList {
other := 8 - v1
// 假设当前的索引是k1,则那另一个数字比较时选择索引位置加一即可。
for k2 := k1 + 1; k2 < len(numberList); k2++ {
if numberList[k2] == other {
fmt.Println(k1, k2)
}
}
// 采用下面的循环方式会重复取索引哟~
// for k2, v2 := range numberList {
// if other == v2 {
// fmt.Println(k1, k2)
// }
// }
}
}