2

In my program I got 2 models:

type User struct {
    Name string
}

type Article struct {
    Title string
}

And I got arrays of data of these structs:

users := []User
articles := []Article

I'm trying to iterate over both of them at the same piece of code:

models := [][]interface{} {users, articles}
for _, model := range models {
    log.Printf("%#v", model)
}

But I'm receiving an error:

cannot use users (type []User) as type []interface {} in array element

What am I doing wrong?

4
  • 1
    This cannot be done. Go is statically typed. Redesign your solution. Commented Sep 4, 2015 at 12:54
  • 2
    You can't convert any slice to []interface{}. For explanation and solution see Type converting slices of interfaces in go. Commented Sep 4, 2015 at 14:27
  • @Volker, icza Thank you, guys. Commented Sep 4, 2015 at 14:43
  • @WhiteAngel the "go way" is using interfaces, I posted a solution that might help :) Commented Sep 4, 2015 at 15:31

3 Answers 3

4

You should use []interface{} instead of [][]interface{}
Try it on the go playground

If you want to iterate all structs in your inner arrays, you need to cast them to the proper type and then iterate, like this:

for _, model := range models {
    if u, ok := model.([]User); ok {
        for _, innerUser := range u {
            log.Printf("%#v", innerUser)
        }
    }
    if a, ok := model.([]Article); ok {
        for _, innerArticle := range a {
            log.Printf("%#v", innerArticle)
        }
    }
}

Try it on the go playground

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you for your response. But this is what I was trying to avoid - switch statement and checking types. In this case I would have repeating blocks that will do absolutely the same things for each type. So, Go doesn't allow you to do this in a clean way? For me the problem is that I might have 10 different models and even more.
Maybe you can use interfaces for that?
@RoninDev like in my answer?
@PabloFernandez exactly
1

How about using interfaces to solve your problem? you can even use the default fmt.Stringer interface, used by fmt.Prtinf and other standard methods.

Example:

package main

import "log"
import "fmt"

type User struct {
    Name string
}

type Article struct {
    Title string
}

func (art Article) String() string {
    return art.Title
}

func (user User) String() string {
    return user.Name
}

func main() {
    models := []interface{}{User{"user1"}, User{"user2"}, Article{"article1"}, Article{"article2"}}
    for _, model := range models {
        printable := model.(fmt.Stringer)
        log.Printf("%s\n", printable)
    }
}

Playground: https://play.golang.org/p/W3qakrMfOd

Comments

1

Maybe I'm not getting your requirements, but what's wrong with just

models := []interface{} {users, articles}
for _, model := range models {
    log.Printf("%#v\n", model)
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.