💜 想真正擅长编程? 从一门课程开始,100% 免费

《笔记》第十四篇 Go切片与Map

第14讲 Go切片与Map

本讲基于视频实际讲解内容整理


一、切片(Slice)简介

老师在上一讲数组的基础上,引入了切片的概念。切片是Go语言中非常重要的数据结构,解决了数组长度固定的限制。


二、切片的定义

切片的声明方式与数组类似,但不需要指定长度:

Go
// 数组:需要指定长度
var arr [3]int

// 切片:不需要指定长度
var s []int

关键区别:数组声明时方括号内有数字(如 [3]int),切片声明时方括号内为空(如 []int)。


三、切片是引用类型

老师特别强调,切片与数组最大的区别在于:切片是引用类型。

切片的底层由三部分构成:

组成部分 说明
指针 指向底层数组的起始地址
长度(len) 当前切片中元素的个数
容量(cap) 从切片起始位置到底层数组末尾的元素个数

因为切片是引用类型,所以对切片的修改会影响到共享同一底层数组的其他切片。


四、append() 添加元素

使用内置函数 append() 向切片中添加元素:

Go
package main

import "fmt"

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

重要注意:append() 的返回值必须赋值回原变量。因为切片是引用类型,当容量不够时,Go会创建一个新的底层数组,此时原切片的指针不会自动更新,必须用返回值重新赋值。

Go
// ✅ 正确写法
s = append(s, 10)

// ❌ 错误写法(不会报错,但元素不会被添加)
append(s, 10)

老师强调:数组不支持 append(),只有切片才能使用 append()。


五、切片删除元素

Go没有提供直接删除切片元素的内置函数,需要手动操作。删除元素的核心思路是:使用 copy() 函数将后面的元素向前移动。

Go
package main

import "fmt"

func main() {
    s := []int{1, 2, 3, 4, 5}

    // 删除下标为2的元素(值为3)
    index := 2
    // 将index之后的元素前移
    copy(s[index:], s[index+1:])
    // 去掉最后一个元素
    s = s[:len(s)-1]

    fmt.Println(s)  // [1 2 4 5]
}

删除步骤:

  1. 用 copy() 把要删除位置后面的元素全部前移一位
  2. 用切片截断去掉最后一个多余元素

六、Map(映射)

6.1 Map的定义

Map是Go中的键值对(key-value)数据结构,定义语法:

Go
// 定义一个key为string、value为int的Map
var m map[string]int

6.2 使用 make() 创建Map

Map是引用类型,声明后需要用 make() 函数分配内存才能使用:

Go
package main

import "fmt"

func main() {
    // 使用make创建Map
    m := make(map[string]int)

    // 添加键值对
    m["张三"] = 90
    m["李四"] = 85

    fmt.Println(m)        // map[张三:90 李四:85]
    fmt.Println(m["张三"])  // 90
}

如果只声明不 make(),直接赋值会报错(nil map不能写入)。


七、Map的类型约束

老师强调了Map的两条重要规则:

7.1 所有key类型必须一致

Go
// ✅ 正确:所有key都是string
m := make(map[string]int)
m["name"] = 1
m["age"] = 2

// ❌ 错误:key类型不一致
m := make(map[string]int)
m["name"] = 1
m[100] = 2  // 编译错误!key必须是string

7.2 所有value类型必须一致

Go
// ✅ 正确:所有value都是int
m := make(map[string]int)
m["a"] = 1
m["b"] = 2

// ❌ 错误:value类型不一致
m["a"] = 1
m["b"] = "hello"  // 编译错误!value必须是int

7.3 key和value类型可以不同

key的类型和value的类型不需要相同,只要各自内部一致即可:

Go
// key是string,value是int —— 完全合法
m := make(map[string]int)

// key是int,value是string —— 也合法
m2 := make(map[int]string)

7.4 key类型必须支持 == 比较

Map的key必须支持 == 运算符进行比较,因为Map需要通过key来查找元素。

key类型 是否可用
string ✅
int/float ✅(但不建议用float)
bool ✅
数组 ✅
指针 ✅
切片 ❌ 不支持比较
Map ❌ 不支持比较
函数 ❌ 不支持比较

老师提醒:浮点数理论上可以做key(因为支持 ==),但不建议使用,因为浮点数精度问题可能导致查找失败。


八、本讲小结

知识点 要点
切片定义 []T,不指定长度
引用类型 切片由指针、长度、容量三部分构成
append() 添加元素,必须赋值回原变量
append() 限制 只有切片可用,数组不可用
删除元素 使用 copy() 前移元素 + 截断
Map定义 map[keyType]valueType
Map创建 使用 make() 分配内存
key约束 所有key类型一致,必须支持 ==
value约束 所有value类型一致
key/value 两者类型可以不同

九、课后练习

  1. 声明一个 []string 切片,用 append() 添加3个名字,打印结果
  2. 尝试对数组使用 append(),观察编译错误信息
  3. 创建一个 map[string]int,存储5个同学的名字和成绩,遍历打印
  4. 尝试创建 map[int]string,观察key和value类型不同时是否合法
  5. 尝试用float64做Map的key,思考为什么老师说不建议这样做