11

我试图了解为什么以下测试代码无法按预期工作:

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是显然被修改了......然后它不是。

有人知道可能是什么问题吗?

4

3 回答 3

18

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
于 2013-05-14T10:18:13.260 回答
2

您的函数是在对象本身上定义的,而不是指向对象的指针。

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是通过引用传递的,并且发生的任何突变都是在原始对象上执行的突变。

于 2013-05-15T02:41:47.607 回答
0

Go 将通过值传递所有内容。这包括函数参数、返回值以及迭代切片、映射或通道时。

如果您将接收器切换到 *Test 类型,则添加到@noj 的答案中,go 将自动使用指针。

于 2019-03-05T15:36:20.473 回答