2017-02-16 45 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 /) –