当前位置: 首页 > 知识库问答 >
问题:

go - 为什么在Go中传递指针 解引用赋值后修改属性不改变原值?

沃威
2024-12-09

指针传参,如果通过解引用获得原值后直接修改属性,则外层属性也会修改。这个很好理解。但为什么再赋值一次,就不是这样的结果呢?

有如下代码

package main

func main() {
    person := Person{age: 10}

    person2 := *(&person)
    person2.age = 30
    println(person.age)
    println(person2.age)
    println("======")

    setAgeByPointer(&person)
    println(person.age)

    println("======")
    setAge(&person)
    println(person.age)

}

type Person struct {
    age int
}

func setAgeByPointer(person *Person) {
    person2 := *person
    person2.age = 55
}

func setAge(person *Person) {
    (*person).age = 55
}

最后的输出结果是这样

10
30
======
10
======
55

一个是
person2 := *person
person2.age = 55

另一个是 (*person).age = 55

为什么上面那个没有修改原值,下面修改了原值,我理解此时都直接修改了原内存地址里的值呀

共有4个答案

郎正平
2024-12-09

第一个和第二个的区别是,第一个是被赋值了,但是被赋值的是person的副本,而不是地址引用-指针,所以被赋值的那个person2修改age,只会影响到person2而已,不会影响person本身。

第二个的虽然也用了&*去折腾了一圈,但是还是本身person,所以你修改age,其实还是对person的修改。

给你增加个例子,这个其实虽然 person3 也是被赋值,但是被赋的是person的指针,也就是内存地址。所以你对person3的修改,其实就是对person本身的修改。

person3 := &person
person3.age = 1000
println(person3.age, person.age)
汪翰墨
2024-12-09
  1. person2 := *person中是先取出person的值然后赋给person2,在Go中struct是值传递的。
  2. age属性是基本类型int,它也是值传递的,所以此处person2.age和person.age是完全独立不相关的,修改不会相互影响。
  3. 如果使用person := &Person{age:10}创建则它是指针类型,此时person2 := person,然后修改person2.age会让person.age一起改变。
  4. 引用传递本质上是通过指针实现的,而在Go中同时存在指针和引用传递(map、slice、chan类型),关于引用传递可以查询深拷贝浅拷贝进行了解。
金英华
2024-12-09

代码分析

main 函数

func main() {
    person := Person{age: 10}
    person2 := *(&person) // 创建 person 的副本
    person2.age = 30 // 修改 person2 的 age 属性
    fmt.Println(person.age) // 打印 person.age,结果为 10
    fmt.Println(person2.age) // 打印 person2.age,结果为 30
    
    setAgeByPointer(&person) // 传递 person 的指针
    fmt.Println(person.age) // 打印 person.age,结果为 10
    
    setAge(&person) // 传递 person 的指针
    fmt.Println(person.age) // 打印 person.age,结果为 55
}

setAgeByPointer 函数

func setAgeByPointer(person *Person) {
    person2 := *person // 创建 person 的副本
    person2.age = 55 // 修改 person2 的 age 属性
}

setAge 函数

func setAge(person *Person) {
    (*person).age = 55 // 直接修改 person 的 age 属性
}

执行流程图

graph TD;
    A[main 函数开始] --> B[创建 person: Person{age: 10}]
    B --> C[person2 := *(&person)]
    C --> D[person2.age = 30]
    D --> E[打印 person.age: 10]
    D --> F[打印 person2.age: 30]
    E --> G[调用 setAgeByPointer(&person)]
    G --> H[person2 := *person]
    H --> I[person2.age = 55]
    I --> J[打印 person.age: 10]
    J --> K[调用 setAge(&person)]
    K --> L[(*person).age = 55]
    L --> M[打印 person.age: 55]

解释

  • 创建副本:当使用 person2 := *(&person) 时,person2person 的一个副本。修改 person2 不会影响 person 的值。
  • setAgeByPointer:在 setAgeByPointer 函数中,person2 := *person 同样是创建了 person 的一个副本。因此,修改 person2 不会影响原始的 person
  • setAge:在 setAge 函数中,(*person).age = 55 直接修改了 personage 属性,因为 person 是通过指针传递的,修改指针指向的值会影响原始变量。
晏望
2024-12-09

person2 := *person这行代码通过解引用person得到一个新的Person值,并赋给person2。此时person2person的一个副本,任何对person2的修改都不会影响person
(*person).age = 55这行代码通过指针修改了personage。由于这里是直接操作指向原始数据的内存地址,因此修改会反映到原始对象上。


在 Go 语言中,所有的参数传递都是通过值传递的方式进行的,都是传递副本。
关于指针和解引用赋值的行为不要混淆。

 类似资料:
  • 我有我的函数,我正在那里填充,但调用这个函数后没有填充,但我知道它是在这个函数中填充的,因为我有那里的输出代码。 我像这样传递指针 为什么它不起作用?谢谢

  • 问题内容: 我正在浏览位于http://tour.golang.org/的golang教程,并在示例29中进行了一些实验。 供您参考,原始示例复制到此处: 这很基本,它显示了如何创建该新结构实例。 但是,示例28显示了如何通过指向它的指针来操纵顶点,因此我对示例进行了一些修改,并对输出感到惊讶。这是修改: 并输出: 使我感到惊讶的不是{4,2},这似乎意味着更改更改了所指向的结构的实例。来自C /

  • 本文向大家介绍为什么我们在C ++中通过引用传递指针?,包括了为什么我们在C ++中通过引用传递指针?的使用技巧和注意事项,需要的朋友参考一下 如果需要修改指针而不是指针指向的对象,则可以按引用传递指针。 这是如何通过引用传递指针的示例- 示例 输出结果

  • Go 函数 引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。 引用传递指针参数传递到函数内,以下是交换函数 swap() 使用了引用传递: /* 定义交换值函数*/ func swap(x *int, y *int) { var temp int temp = *x /* 保持 x 地址上的值 */ *x = *y

  • 在使用一个库的时候碰到了一个很奇怪的问题,有个class实例化生成的对象,假设为A 对A的属性进行修改 打印A发现,其中的a属性并没有变,但是直接打印A.a是改变了的,请问这种情况大概会是什么原因呢,是有什么知识盲区吗,目前知道a属性是不可删除的属性,但是一般对象设置configurable=false也不会出现这种情况,如果不允许修改的话应该也会报错。。 (PS:A只是为了表述简化的例子,并不是

  • 上节课我们学习了 Go 语言中的两种变量声明方式:单变量声明方式和多变量声明方式。既然已经声明了变量,那么下一步肯定要给变量赋值并使用,这节课我们就来学习下在 Go 语言中如何给一个变量赋值: 1. 单变量赋值 Go 语言的赋值使用的是 = 符号,赋值过程可以在变量声明时赋值,也可以在变量声明之后赋值,如果在变量声明时直接赋值,可以不用声明变量类型。需要注意的是 Go 语言变量声明之后会初始化一个

  • 问题内容: 我可以使用指针和值嵌入golang中。通过指针 按价值 通过指针或值更喜欢什么? 问题答案: 这取决于。这里有几种可能性。 如果Renderer按值传递,并且在 Bitmap上定义了Bitmap所需的方法,则需要嵌入 Bitmap。 如果将Renderer作为指针传递,则可以将Bitmap作为值嵌入而没有任何问题(在这种情况下仍可以访问指针方法)。 如果Bitmap具有返回指针的构造函

  • Go支持指针,可以用来给函数传递变量的引用。 package main import "fmt" // 我们用两个不同的例子来演示指针的用法 // zeroval函数有一个int类型参数,这个时候传递给函数的是变量的值 func zeroval(ival int) { ival = 0 } // zeroptr函数的参数是int类型指针,这个时候传递给函数的是变量的地址 // 在函数内部对