Go语言第五章(数组和切片)

数组和切片

数组和切片都是用来存放一组同类型数据的结构,写法也很像,所以放在一起讲。先记住一个关键区别:数组长度固定,切片长度可变

数组

数组的长度在声明时就定死了,之后不能改。元素类型随意,但同一数组里必须是同一种类型。

语法:

go 复制代码
var 数组名 = [长度]类型{值1, 值2, 值3, ...}
数组名 := [长度]类型{值1, 值2, 值3, ...}

例子:

go 复制代码
package main

import "fmt"

func main() {
	var arr = [5]int{1, 2, 3, 4, 5}
	arr2 := [5]int{6, 7, 8, 9, 10}
	fmt.Println(arr, arr2)
}

两种写法都能声明数组:var 完整声明,或 := 短声明。[5]int 表示「长度为 5、元素类型为 int」------长度是类型的一部分[5]int[4]int 是两种不同类型。

读写元素

通过下标访问和修改元素。下标从 0 开始:

go 复制代码
package main

import "fmt"

func main() {
	arr := [4]string{"唱", "跳", "rap", "篮球"}
	// 下标:  0    1     2      3

	fmt.Println(arr[0]) // 唱

	arr[0] = "篮球"
	fmt.Println(arr[0]) // 篮球
}

获取长度

用内置函数 len 获取数组长度:

go 复制代码
package main

import "fmt"

func main() {
	arr := [4]string{"唱", "跳", "rap", "篮球"}
	fmt.Println(len(arr)) // 4
}

切片

切片可以看作「可变长度的数组」。日常开发里用得比数组多得多。

语法上,把数组的长度去掉就行:

go 复制代码
var 切片名 = []类型{值1, 值2, 值3, ...}
切片名 := []类型{值1, 值2, 值3, ...}

例子:

go 复制代码
package main

import "fmt"

func main() {
	var s1 = []int{1, 2, 3}
	s2 := []string{"唱", "跳", "rap"}
	fmt.Println(s1, s2)
}

[]int 没有写死长度,所以这是切片,不是数组。

读写元素

读写方式和数组一样,也是按下标操作:

go 复制代码
package main

import "fmt"

func main() {
	s := []string{"唱", "跳", "rap", "篮球"}

	fmt.Println(s[1]) // 跳

	s[1] = "打球"
	fmt.Println(s) // [唱 打球 rap 篮球]
}

长度与容量

切片有两个常用属性:

  • len:当前元素个数
  • cap:底层数组的容量(还能装多少,不用立刻扩容)
go 复制代码
package main

import "fmt"

func main() {
	s := []int{1, 2, 3}
	fmt.Println(len(s)) // 3
	fmt.Println(cap(s)) // 3
}

切片截取

切片[低:高] 可以从已有切片(或数组)上「切」出一段,得到一个新切片。区间是左闭右开 :包含下标 ,不包含下标

go 复制代码
package main

import "fmt"

func main() {
	s := []int{10, 20, 30, 40, 50}
	// 下标:  0   1   2   3   4

	fmt.Println(s[1:4]) // [20 30 40]  取下标 1、2、3
	fmt.Println(s[:3])  // [10 20 30]  从头切到下标 3(不含 3)
	fmt.Println(s[2:])  // [30 40 50]  从下标 2 切到末尾
	fmt.Println(s[:])   // [10 20 30 40 50]  整段复制一份切片头
}

几种常见写法:

写法 含义
s[低:高] (不含
s[:高] 从开头到 (不含
s[低:] 到末尾
s[:] 整段截取

也可以对数组做同样的事,结果是一个切片:

go 复制代码
package main

import "fmt"

func main() {
	arr := [5]int{10, 20, 30, 40, 50}
	s := arr[1:4]
	fmt.Println(s) // [20 30 40]
}

截取出来的切片和原数据共享底层数组:改一边,另一边也会变。后面做前置追加、中间插入时,会经常用到 s[:idx]s[idx:] 这种写法。

追加元素

切片长度可变,最常见的操作就是往里面加元素。Go 只内置了往尾部 追加的 append;往前面插、往中间插,都要靠 append 和切片截取自己拼。

尾部追加

append 接收原切片和要追加的元素,返回一个新切片。容量不够时会自动扩容:

go 复制代码
package main

import "fmt"

func main() {
	s := []int{1, 2, 3}
	s = append(s, 4, 5)
	fmt.Println(s) // [1 2 3 4 5]
}

一次可以追加多个值。记得把返回值接回来(s = append(...)),否则原切片看不到新增内容。

前置追加

Go 没有「往头部插入」的内置函数,思路是:先建一个装着新元素的切片,再用 append 把原切片接在后面。

这里会用到 ...(展开操作符):s... 表示把切片 s 里的元素一个个拆开,当作多个参数传给 append

go 复制代码
package main

import "fmt"

func main() {
	s := []int{1, 2, 3, 4, 5}
	s = append([]int{-1, 0}, s...)
	// 等同于:append([]int{-1, 0}, 1, 2, 3, 4, 5)
	fmt.Println(s) // [-1 0 1 2 3 4 5]
}

拆开看就两步:

  1. []int{-1, 0}:要插到前面的新元素
  2. s...:把原来的 1, 2, 3, 4, 5 展开,接到后面
中间插入

中间插入同样没有内置方法,本质是把切片拆成「前半段 + 新元素 + 后半段」,再拼回去。

假设切片是 [-1 0 1 2 3 4 5],想在 2 后面(下标 4 的位置)插入 100, 200

go 复制代码
package main

import "fmt"

func main() {
	s := []int{-1, 0, 1, 2, 3, 4, 5}
	// 下标:  0  1  2  3  4  5  6
	idx := 4 // 从下标 4 开始插入,也就是 2 的后面

	s = append(s[:idx], append([]int{100, 200}, s[idx:]...)...)
	fmt.Println(s) // [-1 0 1 2 100 200 3 4 5]
}

这行可以拆成三块理解:

部分 含义 结果
s[:idx] 插入点之前 [-1 0 1 2]
[]int{100, 200} 要插入的内容 [100 200]
s[idx:] 插入点及之后 [3 4 5]

先用 append([]int{100, 200}, s[idx:]...) 得到 [100 200 3 4 5],再接到 s[:idx] 后面,就拼成了最终结果。

写法有点绕,但记口诀就行:前半段 + 新元素 + 后半段

数组 vs 切片

数组 切片
长度 固定,声明时确定 可变,可用 append 增减
类型写法 [5]int []int
传递方式 值拷贝(复制整个数组) 引用底层数组(更轻量)
使用场景 长度已知且不变 日常开发更常用

入门阶段可以先记住:不确定长度、或需要增删,就用切片。

作业

  1. 数组基础 :声明一个长度为 5int 数组,依次赋值为 15,打印第 3 个元素(注意下标),再用 len 打印数组长度。
  2. 切片声明与追加 :声明切片 []string{"唱", "跳", "rap"},用 append 在尾部追加 "篮球",打印切片内容、lencap
  3. 切片截取 :给定 s := []int{10, 20, 30, 40, 50},分别打印 s[1:4]s[:3]s[2:]s[:],对照文中表格核对结果。
  4. 前置与中间插入 :以 []int{1, 2, 3, 4, 5} 为起点,先把 -1, 0 插到最前面;再在元素 3 后面插入 100, 200,最终打印完整切片。
  5. 综合练习 :用切片存储若干门课程分数(如 []int{95, 58, 76, 42, 88})。遍历切片:低于 60 的改为 0(表示重考),然后截取前 3 门课的分数打印,并统计及格科目数量。
相关推荐
AskHarries2 小时前
RSS 有必要做吗
后端
颜进强2 小时前
前端看后端 14:什么是 CORS?
前端·后端
用户69371750013843 小时前
了解一下 Agent Harness
android·前端·后端
swipe3 小时前
16|(前端转全栈)前端人排查后端问题:curl、traceId、日志、MySQL、Redis 怎么用?
前端·后端·面试
亦暖筑序3 小时前
重新认识 AgentScope-Java 2.0:ReActAgent 负责推理,HarnessAgent 负责运行
java·后端·agent
小林ixn3 小时前
Redis 实战避坑指南:从缓存击穿到高可用,一文全搞定
redis·后端
苍何3 小时前
用 AI 做了套品牌周边,感觉能挂Shopify开卖了
后端
用户298698530143 小时前
免费在线将 PDF 转为 Word:5 款好用的转换工具
人工智能·后端
newerp3 小时前
unsafe 包与底层编程
后端