英文:
Why don't changes made to a struct via a method persist?
问题
我试图理解为什么以下测试代码的运行结果与预期不符:
package main
import (
"fmt"
"strings"
)
type Test struct {
someStrings []string
}
func (this Test) AddString(s string) {
this.someStrings = append(this.someStrings, s)
this.Count() // 将打印 "1"
}
func (this Test) Count() {
fmt.Println(len(this.someStrings))
}
func main() {
var test Test
test.AddString("testing")
test.Count() // 将打印 "0"
}
这将打印出:
"1"
"0"
这意味着 someStrings
显然被修改了...然后又没有被修改。
有人知道可能是什么问题吗?
英文:
I'm trying to understand why the following test code is not working as expected:
package main
import (
"fmt"
"strings"
)
type Test struct {
someStrings []string
}
func (this Test) AddString(s string) {
this.someStrings = append(this.someStrings, s)
this.Count() // will print "1"
}
func (this Test) Count() {
fmt.Println(len(this.someStrings))
}
func main() {
var test Test
test.AddString("testing")
test.Count() // will print "0"
}
This would print:
"1"
"0"
Meaning that someStrings
is apparently modified... and then it's not.
Anybody know what could be the issue?
答案1
得分: 19
The AddString method is using a value (copy) receiver. The modification is made to the copy, not the original. A pointer receiver must be used to mutate the original entity:
package main
import (
"fmt"
)
type Test struct {
someStrings []string
}
func (t *Test) AddString(s string) {
t.someStrings = append(t.someStrings, s)
t.Count() // will print "1"
}
func (t Test) Count() {
fmt.Println(len(t.someStrings))
}
func main() {
var test Test
test.AddString("testing")
test.Count() // will print "0"
}
Output
1
1
英文:
The AddString method is using a value (copy) receiver. The modification is made to the copy, not the original. A pointer receiver must be used to mutate the original entity:
package main
import (
"fmt"
)
type Test struct {
someStrings []string
}
func (t *Test) AddString(s string) {
t.someStrings = append(t.someStrings, s)
t.Count() // will print "1"
}
func (t Test) Count() {
fmt.Println(len(t.someStrings))
}
func main() {
var test Test
test.AddString("testing")
test.Count() // will print "0"
}
Output
1
1
答案2
得分: 2
你的函数是在对象本身上定义的,而不是在对象的指针上定义的。
func (this Test) AddString(s string) {
this.someStrings = append(this.someStrings, s)
this.Count() // 将打印"1"
}
上面的函数是在具体的数据上定义的。这意味着当你调用函数时,this
的值作为数据的副本传递进来。所以对this
进行的任何改变都是在副本上进行的(在这种情况下,改变了指向'someStrings'的指针)。我们可以像jnml那样将相同的函数定义在Test的指针上:
func (this *Test) AddString(s string) {
this.someStrings = append(this.someStrings, s)
this.Count() // 将打印"1"
}
如你所见,函数定义是(this *Test)
而不是(this Test)
。这意味着变量this
是通过引用传递的,任何发生的改变都是在原始对象上进行的。
英文:
Your functions are defined on the object themselves rather than a pointer to the object.
func (this Test) AddString(s string) {
this.someStrings = append(this.someStrings, s)
this.Count() // will print "1"
}
The function above is defined on the concrete data. This means that when you call the function, the value of this
is passed in as a copy of the data. So any mutations you do to this
are done on the copy (in this case, the mutation is changing the pointer that 'someStrings' points to. We can rewrite the same function defined on a pointer of Test as jnml did:
func (this *Test) AddString(s string) {
this.someStrings = append(this.someStrings, s)
this.Count() // will print "1"
}
As you can see, the function definition is (this *Test)
instead of (this Test)
. This means that the variable this
is passed by reference, and any mutations that take place are mutations performed on the original object.
答案3
得分: 0
Go将通过值传递所有内容。这包括函数参数、返回值以及在迭代切片、映射或通道时。
要补充@noj的答案,如果将接收器切换为*Test类型,Go将自动使用指针。
英文:
Go is going to pass everything by value. That includes function parameters, return values and when iterating over a slice, map or channel.
to add to @noj's answer if you switch your receiver to *Test type go will use a pointer automatically.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论