使用结构体类型的setter不会按预期工作

huangapple go评论108阅读模式
英文:

Using a setter for a struct type does not work as anticipated

问题

使用结构体的setter函数,但是没有按预期工作:

package main

import "fmt"

type T struct { Val string }

// 这个setter似乎不起作用
func (t T) SetVal( s string ) {
        t.Val = s
}

// 这个setter,使用T的指针,似乎工作正常
func (t *T) SetVal2( s string ) {
        (*t).Val = s
}

func main() {
        v := T{"abc"}
        fmt.Println( v )        // 输出 {abc}
        v.SetVal("pdq")
        fmt.Println( v )        // 输出 {abc},期望输出 {pdq}!
        v.SetVal2("xyz")
        fmt.Println( v )        // 输出 {xyz}!
}

我缺少一些基本的理解 - 为什么SetVal不起作用?

这种行为类似于在reflect中设置值,只有在提供对象的指针时才起作用,而不是对象本身。

英文:

Using a setter function for a struct, but not working as anticipated:

package main

import "fmt"

type T struct { Val string }

// this setter seems not to work
func (t T) SetVal( s string ) {
        t.Val = s
}

// this setter, using ptr to T, seems to work ok
func (t *T) SetVal2( s string ) {
        (*t).Val = s
}

func main() {
        v := T{"abc"}
        fmt.Println( v )        // prints {abc}
        v.SetVal("pdq")
        fmt.Println( v )        // prints {abc}, was expecting {pdq}!
        v.SetVal2("xyz")
        fmt.Println( v )        // prints {xyz}!
}

I am missing some fundamental understanding - why doesn't SetVal work?

the behavior is similar to setting values in reflect which only works if provided a pointer to the object as versus the object itself

答案1

得分: 20

这是你所缺少的基本理解:当一个结构体作为指针传递给函数时,函数可以修改原始结构体,因为它有一个指向它的指针。然而,当一个结构体通过值传递给函数时,实际上为该函数调用创建了一个新的结构体副本,对这个新的结构体副本的任何修改都不会影响原始结构体。

你可以通过打印出相关结构体的实际地址来证明这是它的工作方式:

package main

import "fmt"

type T struct { Val string }

func (t T) SetVal( s string ) {
        fmt.Printf("复制的地址是 %p\n", &t);
}

func (t *T) SetVal2( s string ) {
        fmt.Printf("指针参数是 %p\n", t);
}

func main() {
        v := T{"abc"}
        fmt.Printf("v的地址是 %p\n", &v);
        v.SetVal("pdq")
        v.SetVal2("xyz")
}

当我在Go playground中运行上面的代码时,输出结果如下:

v的地址是 0xf840001290
复制的地址是 0xf8400013e0
指针参数是 0xf840001290

注意,打印出的第一个和第三个指针是相等的,这意味着它们是同一个结构体。但是第二个指针是不同的,因为它是一个副本。

顺便说一下,这似乎与C结构体/函数参数的工作方式完全相同。

英文:

Here is the fundamental understanding you are missing: when a struct is passed in to a function as a pointer, the function can modify the original struct because it has a pointer to it. However, when a struct is passed in to a function via its value, then a NEW copy of the struct is actually created just for that function call, and any modifications to this new copy of the struct will not affect the original struct.

You can prove that this is the way it works by printing out the actual addresses of the structs in question:

package main

import "fmt"

type T struct { Val string }

func (t T) SetVal( s string ) {
        fmt.Printf("Address of copy is %p\n", &t);
}

func (t *T) SetVal2( s string ) {
        fmt.Printf("Pointer argument is %p\n", t);
}

func main() {
        v := T{"abc"}
        fmt.Printf("Address of v is %p\n", &v);
        v.SetVal("pdq")
        v.SetVal2("xyz")
}

The code above results in this output when I run it in the Go playground:

Address of v is 0xf840001290
Address of copy is 0xf8400013e0
Pointer argument is 0xf840001290

Notice how the first and third pointer printed out are equal, which means they are the same struct. But the second pointer is different because it is a copy.

This seems to be exactly the same way that C structs / function parameters work, by the way.

答案2

得分: 1

这是按值调用和按引用调用之间的区别。如果你来自C++背景,那么你会知道在C++中也是一样的。如果你来自Java背景,那么请记住所有对象引用实际上只是指向对象的指针..(也就是说,当我们执行Node node = new Node();时.. node保存的是新创建的节点对象的地址)。因此,对象(node)上的任何方法实际上都是通过引用调用的(因为node本身就是一个指针)..所以它回归到上面的相同示例。

英文:

That's the difference between call by value and call by reference. If you are from C++ background , then you would know that it's the same in C++ also. And if you are from java background, then remember all object references are just pointers to the objects really..(meaning to say, when we do Node node = new Node();.. the node is holding the address of the new node object created). Therefore any method on the object(node) is actually called by reference(because node itself is a pointer).. so it reduces back to the same example as above.

huangapple
  • 本文由 发表于 2011年6月25日 14:51:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/6476343.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定