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」が指すポインターを変更します。jnml が行ったように、Test のポインターで定義された同じ関数を書き直すことができます。

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 に答える