2013-05-14 3 views
7

Я пытаюсь понять, почему следующий тестовый код не работает, как ожидалось:Почему изменения, внесенные в структуру с помощью метода, не сохраняются?

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 изменен ... и тогда это не ,

Кто-нибудь знает, в чем проблема?

ответ

12

Метод 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" 
} 

Playground


Выход

1 
1 
1

Ваших функции определены на самом объекте, а не указатель на объект ,

func (this Test) AddString(s string) { 
    this.someStrings = append(this.someStrings, s) 
    this.Count() // will print "1" 
} 

Функция, указанная выше, определяется конкретными данными. Это означает, что при вызове функции значение this передается как копия данных. Таким образом, любые мутации, которые вы делаете с this, выполняются на копии (в этом случае мутация меняет указатель, на который указывает «someStrings». Мы можем переписать ту же функцию, определенную на указателе теста, как jnml:

func (this *Test) AddString(s string) { 
    this.someStrings = append(this.someStrings, s) 
    this.Count() // will print "1" 
} 

Как вы можете видеть, определение функции является (this *Test) вместо (this Test). Это означает, что переменная this передается по ссылке, и любые мутации, которые происходят мутации, выполненные на исходном объекте.