为什么通过方法对结构体进行的更改不会持久化?

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

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"
}

Playground


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"
}

Playground


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.

huangapple
  • 本文由 发表于 2013年5月14日 18:12:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/16540481.html
匿名

发表评论

匿名网友

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

确定