数组是一组具有相同类型的元素的集合,它们在内存中是连续存储的。数组的长度是固定的,一旦声明后无法改变 。
切片是对数组的抽象,它提供了更灵活的方式来操作数据。切片是一个动态大小的、可以自动扩容的序列。
结构体是一种自定义数据类型,可以封装多个基本数据类型。
选秀活动
某个选秀活动,有三个参赛选手,到会场的观众N个,观众给心仪的选手打分,计算总分数,并获得排名
首先我们定义选手的结构体
type Player struct {
Name string // 姓名
Score int // 得分
}
三个选手来到活动现场后,我们要先明确选手,这样我们就定义Player的数组
// 定义一个数组表示三人信息
var player [3]Player
// 三个选手到位、分别是小张、小李、小王、分数为0
player[0] = Player{Name: "小张", Score: 0}
player[1] = Player{Name: "小李", Score: 0}
player[2] = Player{Name: "小王", Score: 0}
下面是观众了,整场活动现在最大坐席容量为1000人,因为活动方不关心观众的信息,仅关注手中的票投给谁。而且出席观众多少也未知。
// 最大容量
max := 1000
// 定义观众,所以我们就定义一个整型切片
var viewers []int
// 到场的随机观众数
n := rand.Intn(max)
// 前面说了切片有容量,我们给切片开辟n的容量
viewer = make([]int, n)
// 给每个观众发送票
for i := 0; i < n; i++ {
viewer[i] = 1
}
准备工作完成后,我们就可以给选手投票,每个选手上台,展示才艺,观众给投票,要经过3轮
// 选手登场
for i, p := range player {
// 临时记录选手得分
score := 0
// 观众给选手打分
for n, v := range viewer {
// 观众手中没票了就失去投票的权利
if v == 0 {
continue
}
// 0、1的随机数 是否投给选手
s := rand.Intn(2)
// 观众手中票投出
viewer[n] = v - s
// 统计某选手总分
score += s
}
// 把观众投的总分数给选手
p.Score = score
// 更新选手信息
player[i] = p
}
现在经过3轮角逐完成,现在激动人心的时候到了。就是统计所有选手所得分
// 要做排序处理,golang中有对slice排序的函数,可以直接使用
// 素组转化为slice
cal := player[:]
// 对临时slice排序
sort.SliceStable(cal, func(i, j int) bool {
return cal[i].Score > cal[j].Score
})
最后,公示所有选手得分,并决出冠军
fmt.Printf("本场活动总出席观众:%drn", len(viewer))
for i, p := range cal {
fmt.Printf("第%d名 姓名:%s 分数:%drn",
i+1,
p.Name,
p.Score)
}
下面是整体代码,创建main.go文件,写入下面内容
package main
import (
"fmt"
"math/rand"
"sort"
)
type Player struct {
Name string
Score int
}
func main() {
var max int = 1000
var player [3]Player
player[1] = Player{Name: "小李", Score: 0}
player[2] = Player{Name: "小王", Score: 0}
player[0] = Player{Name: "小张", Score: 0}
var viewer []int
// 到场的随机观众数
n := rand.Intn(max)
viewer = make([]int, n+1)
// 给每个观众发送票
for i := 0; i <= n; i++ {
viewer[i] = 1
}
// 开始投票
for i, p := range player {
score := 0
for n, v := range viewer {
// 选观众中没票了就失去投票的权利
if v == 0 {
continue
}
// 是否投给选手
s := rand.Intn(2)
// 观众手中票投产
viewer[n] = v - s
// 统计某选手总分
score += s
}
// 把观众投给她的总票数赋值给选手
p.Score = score
// 更新选手信息
player[i] = p
}
// 统计选手票,并做排名
cal := player[:]
sort.SliceStable(cal, func(i, j int) bool {
return cal[i].Score > cal[j].Score
})
fmt.Printf("本场活动总出席观众:%d人rn", len(viewer))
for i, p := range cal {
fmt.Printf("第%d名 姓名:%s 分数:%drn", i+1, p.Name, p.Score)
}
}
go run main.go 运行程序,结果 如下:
本场活动总出席观众:357人
第1名 姓名:小张 分数:173
第2名 姓名:小李 分数:101
第3名 姓名:小王 分数:45
数组和切片的基本使用
数组和切片变量的声明、初始化、赋值等方式
// 声明数组
var arr [3]string
// 初始化
arr = [3]string{"xiaoli","xiaozhang","xiaowang"}
// 声明并初始化,下面三种定义数组方式作用相同
var arr1 [3]string = [3]string{"xiaoli","xiaozhang","xiaowang"}
// 声明并初始化:数组容量和类型根据初始化决定
var arr2 = [...]string{"xiaoli","xiaozhang","xiaowang"}
// 声明并初始化
arr3 := [3]string{"xiaoli","xiaozhang","xiaowang"}
// 声明切片
var sli []string
// 初始化
sli = []string{"xiaoli","xiaozhang","xiaowang"}
// 声明并赋值
var sli1 []string = [3]string{"xiaoli","xiaozhang","xiaowang"}
// 声明并初始化:切片长度和容量类型根据初始化决定
var sli2 = []string{"xiaoli","xiaozhang","xiaowang"}
// 声明并初始化
sli3 := []string{"xiaoli","xiaozhang","xiaowang"}
// 切片扩容赋值,定义长度2,容量3
sli4 := make([]int,2,3)
sli4[0] = 1
sli4[1] = 2
// 由于定义的长度为2,下面语句是错误
// 运行 runtime error: index out of range [2] with length 2
// sli4[2] = 3
数组是值拷贝、而切片是引用类型
// 声明数组
var arr [3]string
// 初始化
arr = [3]string{"xiaoli", "xiaozhang", "xiaowang"}
funcArr := func(arr [3]string) [3]string {
arr[0] = "edit"
return arr
}
arr1 := funcArr(arr)
fmt.Printf("arr 的指针:%p,arr的值:%v n", &arr, arr)
fmt.Printf("arr1 的指针:%p,arr1的值:%v n", &arr1, arr1)
sli := []string{"xiaoli", "xiaozhang", "xiaowang"}
funcSlic := func(sli []string) []string {
sli[0] = "edit2"
return sli
}
sli1 := funcSlic(sli)
fmt.Printf("sli 的指针:%p,sli的值:%v n", &sli, sli)
fmt.Printf("sli1 的指针:%p,sli1的值:%v n", &sli1, sli1)
}
// 输出结果,在funcArr中复值拷贝,未改变数组值,切片funcSlic把sli和sli1的值改成了edit2
// arr 的指针:0xc0000200f0,arr的值:[xiaoli xiaozhang xiaowang]
// arr1 的指针:0xc000020120,arr1的值:[edit xiaozhang xiaowang]
// sli 的指针:0xc000008048,sli的值:[edit2 xiaozhang xiaowang]
// sli1 的指针:0xc000008060,sli1的值:[edit2 xiaozhang xiaowang]
数组转切片
a := [3]int{1,2,3,4}
// 截取数组为切片长度和容量都等于结束索引-开始索引
a1 := a[1:3] // 索引1,2左闭右开
fmt.Println(a1, len(a1), cap(a1))
// [2 3] 2 2
上面代码底层执行逻辑
切片扩容
// 切片扩容赋值,定义长度和容量
sli4 := make([]int, 2, 3)
sli4[0] = 1
sli4[1] = 2
fmt.Println(sli4, len(sli4), cap(sli4))
sli4 = append(sli4, 5)
fmt.Println(sli4, len(sli4), cap(sli4))
sli4 = append(sli4, []int{7, 8, 9}...)
fmt.Println(sli4, len(sli4), cap(sli4))
// 查看输出结果
// [1 2] 2 3
// [1 2 5] 3 3
// [1 2 5 7 8 9] 6 6
切片的常用截取
// 将切片 b 的元素追加到切片 a 之后
a := make([]int,1)
b :== []int{1,2,3}
a = append(a, b...)
// 复制切片 a 的元素到新的切片 c 上
c := make([]int, len(a))
copy(c, a)
// 删除位于索引 i 的元素,a[:i]0至i-1元素,把a[i+1:]i+1索引到结尾的追加到子切片a[:i]后
a = append(a[:i], a[i+1:]...)
// 切除切片 a 中从索引 i 至 j 位置的元素
a = append(a[:i], a[j:]...)
// 为切片 a 扩展 j 个元素长度
a = append(a, make([]int, j)...)
// 在索引 i 的位置插入元素 3
a = append(a[:i], append([]int{3}, a[i:]...)...)
// 在索引 i 的位置插入长度为 3 的新切片
a = append(a[:i], append(make([]int, 3), a[i:]...)...)
// 索引 i 的位置插入切片 b 的所有元素
a = append(a[:i], append(b, a[i:]...)...)
// 取出位于切片 a 最末尾的元素 x
x := a[len(a)-1]
在我们写代码的过程中,常用切片处理一些同数据类型数据。切片并不直接持有数据,而是引用底层数组的一部分。所以我们这章核心内容就是切片。
更多课程文章一步步带你轻松搭建Go开发环境
运算符、数值类型和输入输出
golang基础03:动手实现聊天机器人
golang基础04: 控制流的使用示例
golang基础05:循环和迭代示例
golang开发工资自发送小软件
原文始发于微信公众号(数据安全治理技术):golang基础06: 一场选秀活动,让你彻底掌握数组和切片的用法
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论