0
votes

I am new to Golang and am trying to append the contents of a slice of struct into another instance. The data gets appended but it is not visible outside the method. Below is the code.

package somepkg

import (
    "fmt"
)

type SomeStruct struct {
    Name  string
    Value float64
}

type SomeStructs struct {
    StructInsts []SomeStruct
}

func (ss SomeStructs) AddAllStructs(otherstructs SomeStructs) {

    if ss.StructInsts == nil {
        ss.StructInsts = make([]SomeStruct, 0)
    }

    for _, structInst := range otherstructs.StructInsts {
        ss.StructInsts = append(ss.StructInsts, structInst)
    }

    fmt.Println("After append in method::: ", ss.StructInsts)
}

Then in the main package I initialize the structs and invoke the AddAllStructs method.

package main

import (
  "hello_world/somepkg"
  "fmt"
)

func main() {
    var someStructs = somepkg.SomeStructs{
      []somepkg.SomeStruct{
        {Name: "a", Value: 1.0},
        {Name: "b", Value: 2.0},
      },
    }

    var otherStructs = somepkg.SomeStructs{
      []somepkg.SomeStruct{
        {Name: "c", Value: 3.0},
        {Name: "d", Value: 4.0},
      },
    }

    fmt.Println("original::: ", someStructs)
    fmt.Println("another::: ", otherStructs)

    someStructs.AddAllStructs(otherStructs)

    fmt.Println("After append in main::: ", someStructs)
}

The above program output is below:

original:::  {[{a 1} {b 2}]}
another:::  {[{c 3} {d 4}]}
After append in method:::  [{a 1} {b 2} {c 3} {d 4}]
After append in main:::  {[{a 1} {b 2}]}

I am trying to understand what I am missing here since the data is visible in the method. Appreciate any help on this.

-- Anoop

3

3 Answers

2
votes

Use pointer receiver:

func (ss *SomeStructs) AddAllStructs(otherstructs SomeStructs) {

    if ss.StructInsts == nil {
        ss.StructInsts = make([]SomeStruct, 0)
    }

    for _, structInst := range otherstructs.StructInsts {
        ss.StructInsts = append(ss.StructInsts, structInst)
    }

    fmt.Println("After append in method::: ", ss.StructInsts)
}

If the method needs to mutate the receiver, the receiver must be a pointer

0
votes

You have to return the result of append:

package main

import (
    "fmt"
)

func main() {
    // Wrong
    var x []int
    _ = append(x, 1)
    _ = append(x, 2)

    fmt.Println(x) // Prints []

    // Write
    var y []int
    y = append(y, 1)
    y = append(y, 2)

    fmt.Println(y) // Prints [1 2]
}
0
votes

You can easily solve this problem by using pointer receiver instead of value receiver.

func (ss *SomeStructs) AddAllStructs(otherstructs SomeStructs) {

    if ss.StructInsts == nil {
        ss.StructInsts = make([]SomeStruct, 0)
    }

    for _, structInst := range otherstructs.StructInsts {
        ss.StructInsts = append(ss.StructInsts, structInst)
    }

    fmt.Println("After append in method::: ", ss.StructInsts)
} 

Remember in go, if you see a slice internals, it is a struct containing pointer to a data structure.

So the slice in the main, doesn't know the capacity of newly appended slice and same slice has been printed.

Secondly , You don't have to return the result of the appended slice. here pointer receiver comes for rescue, as value receivers can't change the original value.

running code at go playground : https://play.golang.org/p/_vxx7Tp4dfN