在go语言中访问指针或值

举报
码乐 发表于 2025/04/17 07:25:53 2025/04/17
【摘要】 1 简介当使用允许访问指针值的编程语言(如 Java、C#、C/C++、Go 等)时,通常必须小心区分按值传递和按引用传递。 按值传递 按引用传递 将函数参数的值复制到另一个变量的机制 将实际参数传递给函数的机制 在函数中所做的更改不会反映在原始值...

1 简介

当使用允许访问指针值的编程语言(如 Java、C#、C/C++、Go 等)时,通常必须小心区分按值传递和按引用传递。

                按值传递                            按引用传递
            将函数参数的值复制到另一个变量的机制         将实际参数传递给函数的机制
            在函数中所做的更改不会反映在原始值中        在函数中所做的更改反映在原始值
            复制实际参数                       实际参数的地址传递给函数
            函数获取实际内容的副本                 函数访问原始变量的内容
            需要更多内存                         需要较少内存
            需要更多时间,因为它涉及复制值           由于没有复制,因此需要的时间更少

分别看看结构体和指针数组在按值和按引用传递时的区别。Go 语言里这两个类型都有明显的行为差异,非常适合用来理解这个概念。

	按值传递:使用按值传递时,函数参数的值将复制到内存中的另一个位置。在该函数中,仅访问或修改变量的副本。因此,原始值不受影响。
	按引用传递:使用按引用传递时,将向该函数提供内存地址。换句话说,该函数可以访问 real 变量。

2 结构体(struct)

  • 按值传递结构体

函数接收的是结构体的副本。修改不会影响原始结构体。

		package main

		import "fmt"

		type Person struct {
		    name string
		    age  int
		}

		func changePerson(p Person) {
		    p.age = 99
		    p.name = "Changed"
		}

		func main() {
		    p := Person{name: "Tom", age: 30}
		    changePerson(p)
		    fmt.Println("main:", p) // 输出: main: {Tom 30}
		}
  • 按引用传递结构体(传指针)

函数接收的是结构体的地址。修改会影响原始结构体。

		func changePersonByRef(p *Person) {
		    p.age = 99
		    p.name = "Changed"
		}

		func main() {
		    p := Person{name: "Tom", age: 30}
		    changePersonByRef(&p)
		    fmt.Println("main:", p) // 输出: main: {Changed 99}
		}

2 针数组(数组中存的是指针)

这是一个有点绕的场景,但也非常常见。我们来仔细看一下。

  • 1 指针数组按值传递(传的是数组副本)

     func changeArray(arr [2]*int) {
         x := 100
         arr[0] = &x // 改变了指针指向
     }
    
     func main() {
         a, b := 1, 2
         arr := [2]*int{&a, &b}
         changeArray(arr)
         fmt.Println(*arr[0]) // 输出: 1,未改变原数组内容
     }
    

虽然修改了 arr[0] 的指针,但只是副本,原数组没变。

    1. 指针数组按引用传递(传指针数组的指针)

                 func changeArrayByRef(arr *[2]*int) {
                     x := 100
                     arr[0] = &x // 修改了原始数组中的指针
                 }
      
                 func main() {
                     a, b := 1, 2
                     arr := [2]*int{&a, &b}
                     changeArrayByRef(&arr)
                     fmt.Println(*arr[0]) // 输出: 100,改变了原数组内容
                 }
      
    1. 修改指针数组中指向的值(不改指向,只改值)

         func modifyPointedValue(arr [2]*int) {
             *arr[0] = 999
         }
      
         func main() {
             a, b := 1, 2
             arr := [2]*int{&a, &b}
             modifyPointedValue(arr)
             fmt.Println(a) // 输出: 999,值被改变
         }
      

虽然数组本身是按值传递,但指针指向的是同一个地址,对值的修改仍然生效。

3 小结

按值传递是指将函数参数值复制到另一个变量的机制,而按引用传递是指将实际参数传递给函数的机制。因此,这是按值传递和按引用传递之间的主要区别。

        类型	   是否需要指针来传引用	    修改指针本身	修改指向的值
        结构体  	    ✅	                  ✅	                ✅
        指针数组         ✅(如果改数组内容)  ✅	             不需要
        数组中的指针值	不需要	          —	             ✅

如果需要处理较大的结构体,推荐用指针传参,减少复制开销。

参考:

https://go.dev/tour/basics/11 https://go.dev/doc/effective_go
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。