了解结构体类型的 Setter
在 Go 中,可以通过 setter 函数修改结构体。但是,在对结构类型使用 setter 时,某些行为可能是无法预料的。考虑以下示例:
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}! }
问题出现了:为什么 SetVal 函数没有按预期修改原始结构?
理解值语义
主要区别在于结构体如何传递给函数。当按值传递结构体时(如 SetVal),会在函数内创建该结构体的副本。函数内所做的任何更改都只会影响此临时副本,而原始结构保持不变。
但是,当通过指针传递结构时(如 SetVal2 中),函数可以访问内存中的原始结构。函数内所做的任何更改都将直接反映在原始结构中。
价值语义证明
这可以通过打印所涉及结构的内存地址来说明:
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") }
此代码将产生输出类似于:
Address of v is 0xf840001290 Address of copy is 0xf8400013e0 Pointer argument is 0xf840001290
注意,打印的第一个和第三个地址是相同的,表明它们引用相同的结构体。然而,第二个地址不同,代表在 SetVal 中创建的临时副本。
以上是为什么我的 Go Struct Setter 函数没有修改原始结构?的详细内容。更多信息请关注PHP中文网其他相关文章!