2017-02-16 33 views
2

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

Примеры (Test3 является то, что я первоначально пытался сделать):

package main 

import (
    "fmt" 
) 

// This works 

type Test1 struct { 
    all []int 
} 

func (c Test1) run() []int { 
    for i := 0; i < 2; i++ { 
    c.all = append(c.all, i) 
    } 
    return c.all 
} 

// This works 

var gloabl_all []int 

type Test2 struct {} 

func (c Test2) run() []int { 
    c.combo() 
    return gloabl_all 
} 

func (c Test2) combo() { 
    for i := 0; i < 2; i++ { 
    gloabl_all = append(gloabl_all, i) 
    } 
} 

// This doesn't 

type Test3 struct { 
    all []int 
} 

func (c Test3) run() []int { 
    c.combo() 
    return c.all 
} 

func (c Test3) combo() { 
    for i := 0; i < 2; i++ { 
    c.all = append(c.all, i) 
    fmt.Println("Test3 step", i + 1, c.all) 
    } 
} 

func main() { 
    test1 := &Test1{} 
    fmt.Println("Test1 final:", test1.run(), "\n") 

    test2 := &Test2{} 
    fmt.Println("Test2 final:", test2.run(), "\n") 

    test3 := &Test3{} 
    fmt.Println("Test3 final:", test3.run()) 
} 

Это выходы:

Test1 final: [0 1] 

Test2 final: [0 1] 

Test3 step 1 [0] 
Test3 step 2 [0 1] 
Test3 final: [] 

площадка копия: https://play.golang.org/p/upEXINUvNu

Любая помощь будет принята с благодарностью!

+0

Необходимо использовать приемник указателя, иначе вы добавите копию. – Volker

ответ

5

Все в Go передается по значению. И копия сделана из переданного значения.

Test3.combo() имеет значение (без указателя) приемник:

func (c Test3) run() []int { 
    c.combo() 
    return c.all 
} 

func (c Test3) combo() { 
    for i := 0; i < 2; i++ { 
    c.all = append(c.all, i) 
    fmt.Println("Test3 step", i + 1, c.all) 
    } 
} 

Это означает, что, когда Test3.combo() вызывается из Test3.run()c.combo(), как, копия сделана из c (который имеет тип Test3). Метод combo() работает с копией. Он правильно добавляет 2 номера в Test3.all, но когда этот метод возвращается, копия отбрасывается.

Так что, когда Test3.run() возвращается c.all, он возвращает пустой (nil) срез, так как срез, к которому прилагается Test3.combo(), было поле копии, и который был отброшен.

Решение: просто использовать указатель приемника:

func (c *Test3) combo() { 
    for i := 0; i < 2; i++ { 
    c.all = append(c.all, i) 
    fmt.Println("Test3 step", i + 1, c.all) 
    } 
} 

Output (попробовать его на Go Playground):

Test1 final: [0 1] 

Test2 final: [0 1] 

Test3 step 1 [0] 
Test3 step 2 [0 1] 
Test3 final: [0 1] 

Обратите внимание на звезду * в приемнике: func (c *Test3) combo(). Добавив его, вы делаете приемник указателем, и поэтому, когда вызывается combo(), он получает только указатель на значение типа Test3, и он будет изменять заочное значение, значение которого Test3.run() имеет, поэтому, когда возвращается combo(), изменения не теряются.

+0

Это было легко! Имеет смысл, спасибо за вашу помощь (это было также полезно: https://nathanleclaire.com/blog/2014/08/09/dont-get-bitten-by-pointer-vs-non-pointer-method-receivers-in -golang /) –