What I'm doing wrong here? Is there some pointer that I'm missing or I missed some logic?
package main
import (
"fmt"
)
type Foo struct {
name string
age string
}
type FooList struct {
group string
foos []Foo
}
func (f *FooList) addFoo(foo Foo) {
f.foos = append(f.foos, foo)
}
func main() {
data := [][]string{{"1a", "11", "12"}, {"1a", "13", "14"}, {"2b", "21", "22"}}
var resultFoo []FooList
for _, d := range data {
if !fInFoo(resultFoo, d[0]) {
foL := FooList{group: d[0]}
resultFoo = append(resultFoo, foL)
}
}
for _, d := range data {
fooList := getFooList(d[0], resultFoo)
foo := Foo{name: d[1], age: d[2]}
fooList.addFoo(foo)
}
fmt.Println(resultFoo)
}
func fInFoo(fooList []FooList, foo string) bool {
for _, fl := range fooList {
if fl.group == foo {
return true
}
}
return false
}
func getFooList(foo string, listOfFoo []FooList) *FooList {
for _, f := range listOfFoo {
if f.group == foo {
return &f
}
}
panic("Couldn't find foo!!")
}
resultFoo always print this result [{1a []} {2b []}] And I expect this [{1a [{11 12} {13 14}]} {2b [{21 22}]}]. Any suggestion is acceptable to solve this problem :)
CodePudding user response:
The problem is in the getFooList function. You are returning a copy of the struct, not a pointer to the struct. This means that when you call addFoo on the returned struct, you are modifying a copy, not the original struct.
To fix this, you can either return a pointer to the struct:
func getFooList(foo string, listOfFoo []FooList) *FooList {
for _, f := range listOfFoo {
if f.group == foo {
return &f
}
}
panic("Couldn't find foo!!")
}
Or you can modify the addFoo function to take a pointer:
func (f *FooList) addFoo(foo *Foo) {
f.foos = append(f.foos, *foo)
}
CodePudding user response:
This is a little bit of a "gotcha". When you take the pointer of f
in getFooList
, you're actually taking a pointer to a copy used in the for range
loop and not the copy in your slice.
func getFooList(foo string, listOfFoo []FooList) *FooList {
for i, f := range listOfFoo {
if f.group == foo {
// using &f here gives a pointer to a copy of FooList,
// but we want a pointer to the copy in our slice
return &listOfFoo[i]
}
}
panic("Couldn't find foo!!")
}
Run it in the playground.
Additionally, this seems like a better spot for a map
if you can use it.
type Foo struct {
name string
age string
}
func main() {
data := [][]string{{"1a", "11", "12"}, {"1a", "13", "14"}, {"2b", "21", "22"}}
resultFoo := make(map[string][]Foo)
for _, d := range data {
group := d[0]
resultFoo[group] = append(resultFoo[group], Foo{name: d[1], age: d[2]})
}
fmt.Println(resultFoo)
}
Run it on the playground.