2017-02-16 46 views
2

我试图给golang slice添加一个值,如果它在第一个方法中被调用,代码就会工作,但是如果这个方法调用另一个方法,代码似乎失败了。为什么我不能追加到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) 
    } 
} 

输出(尝试在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 /) –