一、数组
1. 基本介绍
数组可以存放多个同一类型的数据。数组也是一种数据类型,在 Go 中,数组是 值类型 。
想象一下,数组就像一个固定大小的储物柜,有着明确数量的格子,每个格子只能存放相同类型的物品。一旦这个储物柜建好了,格子的数量就不能改变了。
2. 如何定义数组
var 数组名 [数组大小]数据类型
例如:
var arr [3]int
在Go语言中,定义数组有多种方式:
// 1. 最基础的定义方式
var scores [3]int // 定义一个能存放3个整数的数组
// 2. 定义时直接赋值
var prices = [3]float64{10.99, 20.99, 30.99}
// 3. 让编译器自动计算长度
names := [...]string{"张三", "李四", "王五"}
// 4. 指定特定位置的值
colors := [5]string{0: "红", 2: "蓝", 4: "绿"} // [红 "" 蓝 "" 绿]
2.1. 初始化数组
2.1.1. 普通初始化-声明并初始化
//(1)普通初始化
var arr01 [3]int=[3]int{1,2,3}
fmt.Println("arr01=",arr01)
2.1.2. 省略声明类型-类型推断初始化
//(2)省略声明类型
var arr02 = [3]int{4,5,7}
fmt.Println("arr02=",arr02)
2.1.3. [...]不指定数组元素个数-让编译器推断长度
frameworks := [...]string{"Gin", "Echo", "Fiber", "Beego"}
fmt.Printf("Go Web框架: %v (长度: %d)\n", frameworks, len(frameworks))
2.1.4. 指定位置初始化-指定索引初始化
//(4)指定位置初始化,按数组下标来指定初始化,没被初始化的默认为0
weekdays := [7]string{0: "周一", 1: "周二", 6: "周日"}
fmt.Printf("工作日安排: %v\n", weekdays)
2.1.5. 零值初始化
var userLevels [10]int
fmt.Printf("userLevels: %v\n", userLevels)
3. 数组的特点
- 长度固定:一旦定义,长度不可改变
- 类型固定:同一个数组只能存储相同类型的元素
- 长度是类型的一部分:
[3]int和[5]int是不同的类型
示例:
func SliceDemo1() {
var scores [5]int = [5]int{95, 89, 92, 88, 96}
sum := 0
for _, value := range scores {
sum += value
}
fmt.Println(sum)
average := float64(sum) / float64(len(scores))
fmt.Printf("平均分:%.2f\n", average)
}
输出:
460
平均分:92.0
4. 数组的使用
4.1. 数组的遍历
-
- 方式一:常规遍历
var arr = [...]int{1, 4, 6, 7, 8}
//遍历数组
for i := 0; i < len(arr); i++ {
fmt.Println(arr[i])
} -
- 方式二:for-range 结构遍历
基本语法:
for index,value:=range arr{
...
}
说明:
-
- 第一个返回值 index 是数组的下标
- 第二个 value 是 index 下标对应的值
- index 和 value 是在 for 循环内部的局部变量
- 遍历数组元素的时候,若不想用下标 index,可以直接把下标 index 标位下划线_
- index 和 value 的名称是用户自定义的,一般命名为 index 和 value
案例:
var arr = [...]int{1, 4, 6, 7, 8}
for _, value := range arr {
fmt.Println(value)
}
4.2. 数组使用细节
- 数组是多个相同类型数据的组合,一个数组一旦声明/定义了,其长度是 固定的 ,不能动态变化
- var arr [] int 这时 arr 就是一个 slice 切片
- 数组中的元素可以是任何数据,包括值类型和引用类型,但是不能混用
- 数组的下标是从 0 开始的, 下标必须在指定范围内使用,否则 panic:数组越界
- 数组创建后,若没有赋值,有默认值, 数值 类型默认为 0 , 字符串 类型默认为 "" , bool 类型默认为 false
- Go 的数组属于值类型,在默认情况下是 值传递 ,因此会进行值拷贝,数组间不会相互影响
- 长度是数组类型的一部分,在传递函数参数时,需要考虑数组的长度
4.3. 实际应用
4.3.1. 一维数组的应用,简单模版:
func TemplateManager() {
//类别管理
var templateCategories [6]string
templateCategories[0] = "Go"
templateCategories[1] = "Java"
templateCategories[2] = "Python"
templateCategories[3] = "C#"
templateCategories[4] = "Ruby"
templateCategories[5] = "PHP"
fmt.Println("=== 模板分类 ===")
for index, value := range templateCategories {
fmt.Printf("%d. %s\n", index+1, value)
}
// 每个分类的模板数量统计
templateCounts := [6]int{25, 18, 12, 15, 10, 8}
fmt.Println("\n=== 各分类模板数量 ===")
templateTotal := 0
for i, count := range templateCounts {
fmt.Printf("%s. %d个模版\n", templateCategories[i], count)
templateTotal += count
}
fmt.Printf("总计: %d个模板\n", templateTotal)
// 找出最受欢迎的分类
maxCount := 0
popularCategory := ""
for index, value := range templateCounts {
if value > maxCount {
maxCount = value
popularCategory = templateCategories[index]
}
}
fmt.Printf("最受欢迎的分类: %s (%d个模板)\n", popularCategory, maxCount)
}
输出:
=== 模板分类 ===
-
Go
-
Java
-
Python
-
C#
-
Ruby
-
PHP
=== 各分类模板数量 ===
Go. 25个模版
Java. 18个模版
Python. 12个模版
C#. 15个模版
Ruby. 10个模版
PHP. 8个模版
总计: 88个模板
最受欢迎的分类: Go (25个模板)
4.3.2. 二维数组
多维数组就像一个立体的储物系统,比如一个有多层多排的书架。在实际开发中,多维数组常用于表示表格、矩阵、游戏地图等二维或多维数据。
示例:
func SliceDemo4() {
// 行代表知识点,列代表难度等级(简单、中等、困难)
questionMatrix := [4][3]int{
{15, 8, 3}, // 数据结构题目数量
{12, 10, 5}, // 算法题目数量
{20, 6, 2}, // 基础语法题目数量
{8, 12, 8}, // 系统设计题目数量
}
categories := [4]string{"数据结构", "算法设计", "基础语法", "系统设计"}
difficulties := [3]string{"简单", "中等", "困难"}
fmt.Println("=== 题库分布统计 ===")
fmt.Printf("%-12s", "知识点\\难度")
for _, value := range difficulties {
//输出难度
fmt.Printf("%-8s", value)
}
fmt.Println("总计")
//知识点总数
totalByCategory := [4]int{}
//难度总数
totalByDifficulty := [3]int{}
grandTotal := 0
//遍历知识点
for i, category := range categories {
fmt.Printf("%-12s", category)
categoryTotal := 0
//根据知识点获取难度列表的数量
for j, count := range questionMatrix[i] {
fmt.Printf("%-8d", count)
//知识点总数
categoryTotal += count
//难度总数
totalByDifficulty[j] += count
grandTotal += count
}
totalByCategory[i] = categoryTotal
fmt.Printf("%d\n", categoryTotal)
}
// 打印统计行
fmt.Printf("%-12s", "总计")
for _, value := range totalByDifficulty {
fmt.Printf("%-8d", value)
}
//打印总计数量
fmt.Printf("%-12d\n", grandTotal)
// 分析数据
fmt.Println("\n=== 数据分析 ===")
fmt.Println(totalByCategory[0])
maxCategoryIndex := 0
for index, total := range totalByCategory {
if total > totalByCategory[maxCategoryIndex] {
maxCategoryIndex = index
}
}
fmt.Printf("题目最多的分类: %s (%d题)\n",
categories[maxCategoryIndex], totalByCategory[maxCategoryIndex])
fmt.Printf("简单题占比: %.1f%%\n",
float64(totalByDifficulty[0])/float64(grandTotal)*100)
}
输出:
=== 题库分布统计 ===
知识点\难度 简单 中等 困难 总计
数据结构 15 8 3 26
算法设计 12 10 5 27
基础语法 20 6 2 28
系统设计 8 12 8 28
总计 55 36 18 109
=== 数据分析 ===
26
题目最多的分类: 基础语法 (28题)
简单题占比: 50.5%
4.3.3. 三维数组
示例:
func SliceDemo5() {
// 编程导航学习进度追踪
// 维度:[用户][课程][周数] = 学习时长(小时)
studyProgress := [3][4][4]int{
{ // 用户1: 张三
{2, 3, 4, 5}, // Go基础课程,4周学习时长
{1, 2, 3, 4}, // 算法课程
{0, 1, 2, 3}, // 项目实战
{0, 0, 1, 2}, // 面试准备
},
{ // 用户2: 李四
{3, 4, 5, 6}, // Go基础课程
{2, 3, 4, 5}, // 算法课程
{1, 2, 3, 4}, // 项目实战
{1, 1, 2, 3}, // 面试准备
},
{ // 用户3: 程序员鱼皮
{5, 6, 7, 8}, // Go基础课程
{4, 5, 6, 7}, // 算法课程
{3, 4, 5, 6}, // 项目实战
{2, 3, 4, 5}, // 面试准备
},
}
users := [3]string{"张三", "李四", "Linruxin"}
courses := [4]string{"Go基础", "算法课程", "项目实战", "面试准备"}
fmt.Println("=== 编程导航学习进度报告 ===")
for userIndex, user := range users {
fmt.Printf("\n%s 的学习情况:\n", user)
userTotal := 0
for courseIndex, course := range courses {
fmt.Printf(" %s: ", course)
courseTotal := 0
for week := 0; week < 4; week++ {
hours := studyProgress[userIndex][courseIndex][week]
fmt.Printf("第%d周(%d小时) ", week+1, hours)
courseTotal += hours
userTotal += hours
}
fmt.Printf("- 小计: %d小时\n", courseTotal)
}
fmt.Printf(" 总学习时长: %d小时\n", userTotal)
}
}
输出:
=== 编程导航学习进度报告 ===
张三 的学习情况:
Go基础: 第1周(2小时) 第2周(3小时) 第3周(4小时) 第4周(5小时) - 小计: 14小时
算法课程: 第1周(1小时) 第2周(2小时) 第3周(3小时) 第4周(4小时) - 小计: 10小时
项目实战: 第1周(0小时) 第2周(1小时) 第3周(2小时) 第4周(3小时) - 小计: 6小时
面试准备: 第1周(0小时) 第2周(0小时) 第3周(1小时) 第4周(2小时) - 小计: 3小时
总学习时长: 33小时
李四 的学习情况:
Go基础: 第1周(3小时) 第2周(4小时) 第3周(5小时) 第4周(6小时) - 小计: 18小时
算法课程: 第1周(2小时) 第2周(3小时) 第3周(4小时) 第4周(5小时) - 小计: 14小时
项目实战: 第1周(1小时) 第2周(2小时) 第3周(3小时) 第4周(4小时) - 小计: 10小时
面试准备: 第1周(1小时) 第2周(1小时) 第3周(2小时) 第4周(3小时) - 小计: 7小时
总学习时长: 49小时
Linruxin 的学习情况:
Go基础: 第1周(5小时) 第2周(6小时) 第3周(7小时) 第4周(8小时) - 小计: 26小时
算法课程: 第1周(4小时) 第2周(5小时) 第3周(6小时) 第4周(7小时) - 小计: 22小时
项目实战: 第1周(3小时) 第2周(4小时) 第3周(5小时) 第4周(6小时) - 小计: 18小时
面试准备: 第1周(2小时) 第2周(3小时) 第3周(4小时) 第4周(5小时) - 小计: 14小时
总学习时长: 80小时