理解go指针和值传递

1 简介

在 go社区有句话是: 一切都是值传递, PASS BY VALUE.

当我们传递一个内存地址时,我们传递了一个值

与 C 系列中的所有语言一样,Go 中的所有内容都是通过值传递的。

也就是说,函数总是获取所传递事物的副本,就好像有一个赋值语句将值分配给参数一样。

例如,将 int 值传递给函数会复制 int,传递指针值会复制指针,但不会复制它指向的数据。

本文举例依次说明这几种常见场景。

2 指针的示例

  • 指针引用

该代码使 b 成为指向存储 int 的内存地址的指针,b 的类型为 "int pointer"

arduino 复制代码
    	其中 *int -- * 是类型的一部分 -- b 是 *int 类型
       

代码示例

css 复制代码
	a := 43

  fmt.Println(a)
  fmt.Println(&a)

  var b = *&a

  fmt.Println(b)
  fmt.Println(&b)
  • ** 取消引用**

b 是 int 指针;

b 指向存储 int 的内存地址

要查看该内存地址中的值,请在 b 前面添加一个 * 这称为取消引用,在这种情况下,* 是运算符。

go 复制代码
	a := 43

  fmt.Println(a)   // 43
  fmt.Println(&a)  // 0xc0000180a8
  fmt.Println(*&a) // 43   取消引用

  var b = &a
  fmt.Println(b)   // 0xc0000180a8
  fmt.Println(*b)  // 43
  fmt.Println(&b)  // 0xc000006030
  fmt.Println(*&b) // 0xc0000180a8
 

另一个例子很有用, 我们可以传递一个内存地址而不是一堆值(我们可以传递一个引用) 然后我们仍然可以更改存储在该内存地址中的任何内容的值 这使我们的程序性能更高 我们不必传递大量数据 我们只需要传递地址

go 复制代码
	a := 43 
  fmt.Println(a)  // 43
  fmt.Println(&a) // 0x20818a220

  var b = &a
  fmt.Println(b)  // 0x20818a220
  fmt.Println(*b) // 43

  *b = 42        // b 修改了该地址上的值,改为42  
  fmt.Println(a) // 42
  • 值传递时函数不会改变原参数的值

参数x 传递到 其他函数中 不会改变 参数x的值

go 复制代码
    func zero(z int) {
        z = 0
    }

    func main() {
        x := 5
        zero(x)  // 参数 传递到 其他函数中 不会改变 参数的值
        fmt.Println(x) // x is still 5
    }
  • 值传递时使用指针修改原参数的值

参数x 的地址,被传递到函数中, 函数中取消了引用,并改变 传入参数的值

go 复制代码
func zero(z *int) {
    fmt.Println("from function zero ", z)   //0xc00000a0c8
    *z = 0  //指针加指针 指向了原值
}

func main() {
    x := 5
    fmt.Println(&x)   //0xc00000a0c8
    zero(&x)
    fmt.Println(x) // x 被修改为 0 
}

3 零值汇总

在 Go 语言中,变量定义可以是声明的,也可以通过 make 、 new 函数来声明,

区别在于 make 和 new 函数属于显式声明 display declaration(返回变量实例) 和初始化 initialization(new 返回实例的指针地址)。

如果我们声明的变量未显式初始化,则变量的默认值是该类型的零值。

测试代码

go 复制代码
    var (
        a     [2]int32
        iface interface{}
        it    int32
        ft    float32
        ct    chan int
        st    string
        strct struct{}
        sl    []int32
        mp    map[int]int
        pt    *int
        fct   func()
    )

    fmt.Println("zero of array:", a)
    fmt.Println("zero of interface:", iface)
    fmt.Println("zero of int32:", it)
    fmt.Println("zero of float32:", ft)
    fmt.Println("zero of chan:", ct)
    fmt.Println("zero of string:", st)
    fmt.Println("zero of struct:", strct)
    fmt.Println("zero of slice:", sl)
    fmt.Println("zero of map:", mp)
    fmt.Println("zero of *int:", pt)
    fmt.Println("zero of fuction:", fct)

输出示例:

go 复制代码
zero of array: [0 0]
zero of interface: <nil>
zero of int32: 0
zero of float32: 0
zero of chan: <nil>
zero of string:
zero of struct: {}
zero of slice: []
zero of map: map[]
zero of *int: <nil>
zero of fuction: <nil>

4 小结

如果将变量传递给函数,该函数总是会得到它的副本。

因此,调用方和被调用方有两个具有相同值的自变量。

如果被调用方修改了 parameter variable,则效果对调用方不可见。

认识到 Go 总是通过值传递,再加上支持指针的额外表现力,我们就能创建出更清晰的程序。

相关推荐
野犬寒鸦29 分钟前
Linux常用命令详解(下):打包压缩、文本编辑与查找命令
linux·运维·服务器·数据库·后端·github
huohuopro1 小时前
thinkphp模板文件缺失没有报错/thinkphp无法正常访问控制器
后端·thinkphp
陌尘(MoCheeen)4 小时前
技术书籍推荐(002)
java·javascript·c++·python·go
cainiao0806054 小时前
《Spring Boot 4.0新特性深度解析》
java·spring boot·后端
-曾牛4 小时前
Spring AI 与 Hugging Face 深度集成:打造高效文本生成应用
java·人工智能·后端·spring·搜索引擎·springai·deepseek
南玖yy4 小时前
C/C++ 内存管理深度解析:从内存分布到实践应用(malloc和new,free和delete的对比与使用,定位 new )
c语言·开发语言·c++·笔记·后端·游戏引擎·课程设计
计算机学姐5 小时前
基于SpringBoot的小区停车位管理系统
java·vue.js·spring boot·后端·mysql·spring·maven
BUG制造机.5 小时前
Go 语言 slice(切片) 的使用
开发语言·后端·golang
小鸡脚来咯5 小时前
请求参数:Header 参数,Body 参数,Path 参数,Query 参数分别是什么意思,什么样的,分别通过哪个注解获取其中的信息
java·spring boot·后端
天上掉下来个程小白6 小时前
添加购物车-02.代码开发
java·服务器·前端·后端·spring·微信小程序·苍穹外卖