Golang学习笔记:深入理解Array、Slice与Map

山间有风
山间有风
发布时间:2026-10-13 | 3人浏览过
原创

在Go语言开发中,熟练掌握数组、切片和哈希表(Map)是构建高效程序的基础。本文将深入解析这三种数据结构的特性、底层实现机制及常用操作,对比其与Python等语言的差异,重点阐明值传递与引用的区别,以及make与new函数的使用场景。

一、数组(Array):基于值的类型

在Go语言中,数组是一个固定长度的同类型元素序列,属于值类型(Value Type)。这意味着所有涉及数组的变量赋值或函数参数传递,都会触发一次完整的数据复制动作。

第1步:理解数组的底层行为

由于是值类型,若将数组作为函数参数传入,函数体内获得的是原数组的一个副本,直接修改函数内的数组内容不会影响外部原始数组。如果需要在函数中修改数据,通常建议使用指向数组的指针或改用切片。

第2步:声明与初始化

数组的长度是其类型的一部分,例如 [3]int 和 [4]int 被视为完全不同的类型。以下是几种常见的定义方式:

  1. 基础声明:
    代码:`var a [5]int`。默认初始化为零值(整数为0),输出结果为 `[0 0 0 0 0]`。
  2. 二维数组:
    代码:`var c [2][3]int`。支持多维嵌套定义。
  3. 直接赋值:
    代码:`b := [5]int{1,2,3,4,5}`。
    代码:`d := [...]int{4,5,6}`,使用 `...` 自动推断长度。
  4. 索引指定:
    代码:`e := [...]int{19:3}`。仅设置第20个元素为3,其余补0。

注意:对于嵌套数组,最内层的长度必须显式给出。例如:[2][4]int{{1,2,3,4}, {1,2,3,4}} 是正确的,但省略内部长度会导致编译错误。

第3步:元素的获取与操作

数组可以通过下标访问,也支持通过 range 遍历。可以使用 len() 函数获取数组长度,该长度在编译期即确定且不可变。

// 传统循环
for i:=0; i < len(array); i++ {
    fmt.Println(i, array[i])
}

// 推荐:使用 range 同时获取索引和值
for i, v := range array {
    fmt.Println(i, v)
}

指针与地址的区别:
使用 new([10]int) 会返回一个指向新分配数组的指针(类型为 *[10]int)。而 &a(其中 a 是已定义的数组)同样可以获取其地址并赋给对应类型的指针变量。

二、切片(Slice):动态扩展的引用

Slice 并非简单的数组指针,它是一个包含三个字段的数据结构:指向底层数组的指针、长度(Length)以及容量(Capacity)。它是引用类型,多个 Slice 指向同一底层数组时会共享内存状态。

第1步:创建切片

切片可以通过数组切片(Slicing)、make 函数或直接字面量创建:

  1. 从数组派生:
    语法格式为 array[start:end]。左闭右开区间。
    示例:`a := [5]int{1,2,3,4,5}`,则 `b := a[1:3]` 得到 [2 3]。
  2. 使用 make:
    `myslice := make([]int, 5, 10)`。第一个参数是长度,第二个参数是容量。
  3. 直接构造:
    `c := []int{1,2,3}`。

第2步:关键操作:追加与拷贝

  • Append(追加):
    append(slice, val) 会将元素添加到切片末尾并返回新的切片。当切片的容量不足时,Go会自动重新分配更大的底层数组。这会带来隐患:如果旧容量充足,修改会影响所有引用该底层的切片;如果触发了扩容,新建的底层数组与原数组隔离,导致后续操作出现非预期结果。
  • Copy(拷贝):
    copy(dst, src) 将源切片复制到目标切片,返回实际复制的元素个数。以两者长度较短的那个为准。
s1 := []int{1,2,3,4,5}
s2 := []int{5,4,3}
copy(s1, s2) // s1 变为 [5,4,3,4,5]

排错提示:如果在循环中使用 Append 频繁向切片添加元素,且没有预设足够容量,可能会导致性能下降,建议预先计算所需长度或使用 make 指定容量。

三、映射(Map):无序的键值对

类似于 Python 中的字典,Map 是无序的键值对集合。Key 类型必须是可比较的(如 int, string, slice/func/map 不能作为 Key),Value 可以是任意类型。

第1步:声明与初始化

Map 在使用前必须初始化(否则为 nil map,无法写入):

// 方式1:make 初始化
numbers := make(map[string]int)
numbers["one"] = 1

// 方式2:字面量初始化
rating := map[string]float32{"C":5, "Go":4.5}

第2步:读写操作

  • 赋值:m[key] = value。
  • 删除:delete(m, key)。即使 Key 不存在也不会报错。
  • 安全取值:
    为了避免取值时遇到未找到 Key 的问题,推荐使用“逗号-ok”惯用法:
val, ok := rating["Java"]
if ok {
    fmt.Println(val)
} else {
    fmt.Println("Key not found")
}

四、深度辨析:Make 与 New

许多初学者容易混淆这两个关键字的作用域与返回值:

特性 new(T) make(T)
用途 为基本类型或结构体分配内存 专用于内建类型:slice, map, channel
返回值 返回指向 T 的指针 (*T) 返回初始化的 T 实例本身 (非指针)
内存状态 零值填充,完全独立 带有初始数据结构(如 Map 的桶结构),可直接使用

总结:new 只是把内存清为零;而 make 不仅分配内存,还执行了必要的初始化过程。对于 Map 和 Slice,直接使用 make 生成的对象才是可用的。

以上就是 Golang Array、Slice 和 Map 核心用法的详细内容,更多关于 Go 语言进阶学习的资料请关注本站其它相关文章!
相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表