1

I tried searching, but can't find how to do this. I want to take instances of my struct and store them in a list, then iterate over them and call a function on them.

type comicBook struct {
    Title     string
    Writer    string
    Artist    string
    Publisher string
    Year      int
    Pages     int
    Grade     float32
}
func (c comicBook) PrintInfo() {
    fmt.Println(c.Title, "written by", c.Writer, "drawn by", c.Artist, "published by", c.Publisher, "in", c.Year)
    fmt.Println("Pages:", c.Pages)
    fmt.Println("Grade:", c.Grade)
}

This works fine.

c := comicBook.NewComicBook(
        "Mr. GoToSleep",
        "Tracey Hatchet",
        "Jewel Tampson",
        "DizzyBooks Publishing Inc.",
        1997,
        14,
        6.5,
    )

c.PrintInfo()

c2 := comicBook.NewComicBook("Epic Vol. 1",
        "Ryan N. Shawn",
        "Phoebe Paperclips",
        "DizzyBooks Publishing Inc.",
        2013, 160, 9.0)

c2.PrintInfo()

Storing them in a list does not.

comicBookList := list.New()
    comicBookList.PushBack(c)
    comicBookList.PushBack(c2)

    fmt.Println("\nNow from a list!\n")

    for comic := comicBookList.Front(); comic != nil; comic = comic.Next() {
        comic.Value.PrintInfo()
    }

This fails with comic.Value.PrintInfo undefined (type interface {} is interface with no methods)

galamdring
  • 303
  • 1
  • 7
  • You may want to check this post https://stackoverflow.com/questions/18926303/iterate-through-the-fields-of-a-struct-in-go . – infiniteLearner Dec 06 '19 at 14:05
  • What list type are you using? And why are you using it instead of just using a slice? – Adrian Dec 06 '19 at 15:47
  • @Adrian I am just learning Go, coming from C#. I had expected List to be a basic container, I was not aware of slices yet. The answer icza gave cleared up my issues. – galamdring Dec 12 '19 at 12:03
  • I'd recommend starting with the official docs then. Take the [Tour of Go](https://tour.golang.org/welcome/1), which covers all the language basics (including slices). Also read [Effective Go](https://golang.org/doc/effective_go.html), which covers fundamentals as far as how to think about and write good Go code. – Adrian Dec 12 '19 at 15:29

2 Answers2

3

container/list is not "generic" and operates on interface{} values. To get "typed" values out of it, you have to use type assertion:

for comic := comicBookList.Front(); comic != nil; comic = comic.Next() {
    comic.Value.(comicBook).PrintInfo()
}

Try it on the Go Playground.

But you shouldn't use container/list in the first place.

Instead use a slice. Slices are generic (with the help of the compiler):

var books []comicBook

To add a value to the slice, use the builtin append():

b := comicBook.NewComicBook(...)
books = append(books, b)

To iterate over the slice, use for range:

for _, b := range books {
    b.PrintInfo()
}

Try it on the Go Playground.

icza
  • 389,944
  • 63
  • 907
  • 827
  • Thank you. This makes much more sense than the list approach. – galamdring Dec 06 '19 at 14:24
  • I'm actually having issues implementing this. The comicBook struct is in another file(just to try to work through managing imports as well) and since its lower case, it's not exported. I tried making it capital and doing var comicBookList []comicBook.ComicBook but that is erroring on the next line that comicBook.ComicBook has no field or method append. – galamdring Dec 06 '19 at 15:27
  • 1
    @galamdring `append()` is not a method, it's a function. Please check again how you use it: `books = append(books, b)` – icza Dec 06 '19 at 15:29
0

@icza's answer is the best approach. That said, you can use type assertion.

for comic := comicBookList.Front(); comic != nil; comic = comic.Next() {
    realComic, ok := comic.Value.(comicBook)
    if !ok {
        panic("this would error anyway, but good for visibility")
    }
    realComic.PrintInfo()
}
Jim Wright
  • 5,905
  • 1
  • 15
  • 34