我试图理解为什么以下测试代码没有按预期工作:
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"
}
这将打印:
"1"
"0"
意味着someStrings
显然已被修改......然后它不是。
有人知道会出现什么问题吗?
答案 0 :(得分:15)
AddString方法使用值(复制)接收器。对副本进行修改,而不是原始副本。必须使用指针接收器来改变原始实体:
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"
}
输出
1
1
答案 1 :(得分:1)
您的函数是在对象本身上定义的,而不是指向对象的指针。
func (this Test) AddString(s string) {
this.someStrings = append(this.someStrings, s)
this.Count() // will print "1"
}
上面的函数是在具体数据上定义的。这意味着当您调用该函数时,this
的值将作为数据的副本传入。所以你对this
所做的任何突变都是在副本上完成的(在这种情况下,变异正在改变'someStrings'所指向的指针。我们可以重写在test的指针上定义的相同函数,如jnml所做的那样:
func (this *Test) AddString(s string) {
this.someStrings = append(this.someStrings, s)
this.Count() // will print "1"
}
如您所见,函数定义为(this *Test)
而不是(this Test)
。这意味着变量this
通过引用传递,并且发生的任何突变都是对原始对象执行的突变。
答案 2 :(得分:0)
Go将通过价值传递一切。其中包括函数参数,返回值以及在切片,映射或通道上进行迭代时。
如果将接收器切换为*测试类型,则添加到@noj的答案中,go将自动使用指针。