9

I want to initialize a map containing a list of interface without having to add them one by one:

type Pixel struct {
    X float64
    Y float64
}

type Vertex struct {
    X float64
    Y float64
    Z float64
}
type testpair struct {
    filename       string
    values     []interface{}
}
var tests = map[string]testpair{
   "test1": {
               filename: "file1.csv",
               values:  []Pixel{
                           {X: 12.5, Y: 23.4},
                           {X: 17.2, Y: 7.9},
                      }
            },
   "test2": {
               filename: "file2.csv",
               values:  []Vertex{
                           {X: 10.7, Y: 13.3, Z: 25.1},
                           {X: 18.3, Y: 16.9, Z: 16.4},
                      }
            }, 
}

The compiler would output such an error:

cannot use []Pixel literal (type []Pixel) as type []interface {} in field value

If I switch []interface{} to []Pixel, I can initialize the map but I can do it only with a unique type Pixel or Vertex.

Is there a way to force the compiler to accept array initialization with a specific struct while declaring it as an array of interface?

1
  • 5
    replace []Pixel{ {X:...}, {X:...}} with: []interface{}{ Pixel{X:...}, Pixel{X:...}}. Commented Sep 3, 2018 at 12:53

4 Answers 4

18

If you have to create a slice of values for passing to something that requires a slice of interface{} (which, depending on the context, may or may not be appropriate design) or a slice of any more specific interface, you have to specify each element fully, like this:

[]interface{}{ 
    Pixel{X: 12.5, Y: 23.4},
    Pixel{X: 17.2, Y: 7.9},
}

That also means that you can pass things like:

[]interface{}{
    Pixel{X: 12.5, Y: 23.4},
    Vertex{X: 10.7, Y: 13.3, Z: 25.1},
}

which is hardly something you intended, and compiler won't warn you. I don't see that a big deal for the testing code, though.

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

Comments

3

Is there a way to force the compiler to accept array initialization with a specific struct while declaring it as an array of interface?

No. Basically you cannot force the Go compiler to anything.

See also the FAQ: https://golang.org/doc/faq#convert_slice_of_interface

You must supply a []interface{}.

But please stop doing this and come up with something not requiring the empty interface.

5 Comments

just curious why did you mention, "come up with something not requiring the empty interface", any article for further reading?
What I am trying to do is to create a container that holds instances of objects inheriting from the same parent object, I used a pure interface here to make things easy to understand but it could be my own custom interface.
@AmineKerkeni inheritance is not a thing in Go.
@AmineKerkeni The empty interface is not a "pure" interface, it is a worm of cans and other stuff. If you want to collect two different things (Pixels and Vertices) look what operations you perform on them in common. Extract that into an interface and let your container hold that interfaces. If you never do the same stuff to your elements: Don't carry them in the same container.
@volker is right. Most times you find yourself using interface{} you should really be doing something more specific. It's like using void * in C, which is much abused (and can almost always be replaced using incomplete types.) You're throwing away the type checking facility, which is a powerful tool to help catch bugs at compile time. There's a simple test. If you really want to be able to use ANY type, interface{} is correct. Otherwise, it's probably not.
1

I had the same problem but was about to use primitives so this suggested solution here want work. In that case I helped my self out with:

args := make([]interface{}, 2)
args[0] = "some string"
args[1] = 1 //some int

Comments

0

To be able to initialize you need to input a type to the interface and not an array of type, so suggest you to change as follow:

    type Pixel struct {
    X float64
    Y float64
}
type Pixels []Pixel

type Vertex struct {
    X float64
    Y float64
    Z float64
}
type Vertexs []Vertex
type testpair struct {
    filename string
    values   interface{}
}
var tests = map[string]testpair{
    "test1": {
        filename: "file1.csv",
        values: Pixels{
            Pixel{X: 12.5, Y: 23.4},
            Pixel{X: 17.2, Y: 7.9}}},
    "test2": {
        filename: "file2.csv",
        values: Vertexs{
            Vertex{X: 10.7, Y: 13.3, Z: 25.1},
            Vertex{X: 18.3, Y: 16.9, Z: 16.4}}}}

2 Comments

Creating the Pixels and Vertexs types is unnecessary here, you could just do values: []Pixel{...} if you wanted to do it this way.
Yes @Adrian sure you could do that too but just to make it clearer ( I usually do that)

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.