Golang如何理解指针与slice、map的区别

来源:APP编程网作者:沙月恵奈‌头衔:网络博主
导读:本期聚焦于小伙伴创作的《Golang如何理解指针与slice、map的区别》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Golang如何理解指针与slice、map的区别》有用,将其分享出去将是对创作者最好的鼓励。

Golang中的指针、slice和map是开发中经常用到的概念,很多初学者会误以为slice和map是指针的一种,或者不清楚三者在数据传递时的行为差异,导致代码出现不符合预期的结果。接下来我们从内存模型、传递规则、修改影响三个维度逐一分析三者的区别。

Golang如何理解指针与slice、map的区别

一、Golang指针的核心特性

指针是存储另一个变量内存地址的变量,在Golang中通过*声明指针类型,通过&获取变量地址。指针传递时,传递的是地址的拷贝,但是两个地址指向同一个内存空间,因此修改指针指向的内容会影响原始变量。

1.1 指针的基础示例

下面通过一个简单的示例看指针的传递和修改行为:

package main

import "fmt"

// 接收int类型指针的函数
func modifyByPointer(num *int) {
    // 修改指针指向的内容
    *num = 20
}

func main() {
    a := 10
    fmt.Println("修改前a的值:", a) // 输出 10
    // 传递a的地址给函数
    modifyByPointer(&a)
    fmt.Println("修改后a的值:", a) // 输出 20
}

1.2 指针传递的本质

当把指针作为参数传递时,函数接收的是指针值的拷贝,也就是一个新的指针变量,但是这个新的指针和原始指针指向同一个内存地址。如果我们在函数内修改指针本身的指向(比如让指针指向新的地址),不会影响原始指针的指向,只会修改当前拷贝的指针变量。

package main

import "fmt"

func changePointer(p *int) {
    // 让拷贝的指针指向新的变量
    newNum := 30
    p = &newNum
}

func main() {
    a := 10
    p := &a
    fmt.Println("修改前p指向的值:", *p) // 输出 10
    changePointer(p)
    // p仍然指向a,没有变化
    fmt.Println("修改后p指向的值:", *p) // 输出 10
}

二、Slice的底层结构与传递规则

Slice是Golang中的引用类型,它的底层结构包含三个部分:指向底层数组的指针、切片的长度len、切片的容量cap。当我们传递slice时,传递的是slice结构体的拷贝,这个拷贝的slice和原始slice共享同一个底层数组。

2.1 Slice的修改行为示例

下面示例展示slice传递后的修改影响:

package main

import "fmt"

// 接收slice参数的函数
func modifySlice(s []int) {
    // 修改slice第一个元素
    s[0] = 100
    // 给slice追加元素
    s = append(s, 200)
}

func main() {
    arr := []int{1, 2, 3}
    fmt.Println("修改前slice:", arr) // 输出 [1 2 3]
    modifySlice(arr)
    // 第一个元素被修改,但是追加的元素没有同步到原slice,因为append可能返回新的slice结构体
    fmt.Println("修改后slice:", arr) // 输出 [100 2 3]
}

2.2 Slice与指针的核心差异

Slice本身不是指针,它只是一个包含指针的结构体。如果我们将slice作为参数传递,修改slice结构体的len或者cap不会影响原始slice,但是修改底层数组的内容会影响原始slice,因为底层数组是共享的。而指针传递时,修改指针指向的内容才会影响原始变量,修改指针本身不会影响原始指针。

三、Map的底层结构与传递规则

Map也是Golang中的引用类型,它的底层是一个哈希表的指针,传递map时,传递的是这个哈希表指针的拷贝,因此所有的map拷贝都指向同一个哈希表,修改map的内容会影响所有引用这个map的变量。

3.1 Map的修改行为示例

下面示例展示map传递后的修改影响:

package main

import "fmt"

// 接收map参数的函数
func modifyMap(m map[string]int) {
    m["a"] = 100
    // 删除map中的元素
    delete(m, "b")
}

func main() {
    myMap := map[string]int{"a": 1, "b": 2}
    fmt.Println("修改前map:", myMap) // 输出 map[a:1 b:2]
    modifyMap(myMap)
    // 修改和删除操作都同步到了原map
    fmt.Println("修改后map:", myMap) // 输出 map[a:100]
}

3.2 Map与Slice的差异

Map和Slice都是引用类型,但是map的底层是指向哈希表的指针,所以不管怎么传递map,只要修改map的内容,都会反映到原始的map中。而slice的底层是包含指针的结构体,当slice发生扩容时,append会返回一个新的slice结构体,指向新的底层数组,这时候修改新slice的内容不会影响原始slice。

四、三者的核心区别总结

我们可以通过一个对比表格清晰看到三者的差异:

类型底层结构传递内容修改内容的影响
指针存储变量的内存地址地址值的拷贝修改指向的内容会影响原始变量,修改指针本身不影响原始指针
Slice包含底层数组指针、len、cap的结构体slice结构体的拷贝修改底层数组内容会影响原始slice,修改slice结构体本身(如len、cap)不影响原始slice,扩容后新slice和原始slice解绑
Map指向哈希表的指针哈希表指针的拷贝修改map内容会影响所有引用该map的变量

五、实际使用场景建议

  • 如果需要传递大的结构体,并且需要修改原始结构体的内容,优先使用指针传递,避免值拷贝的开销。
  • 如果需要动态扩容的有序集合,使用slice,注意append后的返回值需要重新赋值给原始slice才能保持同步。
  • 如果需要键值对的无序集合,使用map,不需要额外传递指针就能在函数内修改原始map的内容。

理解三者的本质差异后,就能在开发中准确判断数据传递后的行为,避免写出不符合预期的代码。

Golang指针slicemap引用类型修改时间:2026-06-20 01:39:40

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。