1

Hi I am very new to Golang, please help me. I have defined a struct inside a struct. But I get an error when I try to initialise the main struct.

type DetailsFilter struct {
  Filter struct {
    Name    string        
    ID      int                           
  } 
}

var M map[string]interface{}
M = make(map[string]interface{})
M["Filter"] = map[string]interface{}{"Name": "XYZ", "ID": 5}
var detailsFilter = DetailsFilter{Filter: M["Filter"]}}

The error I get is : can not use (type interface {}) as type struct in field value : need type assertion.

Please suggest a way to initialise DetailsFilter. I tried doing the method described in Initialize a nested struct in Golang, but even this is not working.

Community
  • 1
  • 1
user2709885
  • 413
  • 2
  • 8
  • 16
  • 2
    If you are "very new to Go" you might want to keep away from `interface{}` for some days or even weeks. – Volker May 07 '15 at 14:15

2 Answers2

6

Unfortunately if the type of a struct field is an anonymous struct, at construction time you can only initialize it by "duplicating" the anonymous struct type (specifying it again):

type DetailsFilter struct {
    Filter struct {
        Name string
        ID   int
    }
}

df := DetailsFilter{Filter: struct {
    Name string
    ID   int
}{Name: "myname", ID: 123}}
fmt.Println(df)

Output:

{Filter:{Name:myname ID:123}}

Shorter Alternative

So instead I recommend not to initialize it at construction, but rather after the zero-valued struct has been created, like this:

df = DetailsFilter{}
df.Filter.Name = "myname2"
df.Filter.ID = 321
fmt.Printf("%+v\n", df)

Output:

{Filter:{Name:myname2 ID:321}}

Try it on the Go Playground.

Naming the anonymous struct type

Or don't use anonymous struct as field type at all, name the type like this:

type Filter struct {
    Name string
    ID   int
}

type DetailsFilter struct {
    Filter Filter
}

And then you can simply initialize it like this:

df := DetailsFilter{Filter: Filter{Name: "myname", ID: 123}}
fmt.Printf("%+v\n", df)

Output (try it on the Go Playground):

{Filter:{Name:myname ID:123}}
icza
  • 389,944
  • 63
  • 907
  • 827
0

The type of M["Filter"] to the compiler is interface{}. The type to the runtime is map[string]interface{}. Neither of those is convertable to your anonymous struct type for the Filter field.

You should define a type for filter, or just not have it at all. Why not

type DetailsFilter struct {
   Name    string        
   ID      int                           
} 

M := make(map[string]*DetailsFilter)
M["Filter"] = &DetailsFilter{"Name": "XYZ", "ID": 5}
var detailsFilter = M["Filter"]

I am not sure why you need the nested anonymous struct at all. In general it is not needed to use interface{} unless you really need to. It is usually a sign you are fighting the type system instead of embracing it.

The reason You should not use an anonymous struct like that is that there is no clean way to intialize it. You have two options:

1- Repeat the type definition in the struct literal:

x := DetailsFilter{Filter: struct {
    Name string
    ID   int
}{Name: "Foo", ID: 5}}

2- Set individual fields:

x := DetailsFilter{}
x.Filter.Name = "Foo"
x.Filter.ID = 5

It seems easier to create a real type for the nested field if you want to create them with struct literals.

captncraig
  • 22,118
  • 17
  • 108
  • 151
  • Thank you for your answer. Can you please explain me how to initialise nested anonymous struct if I need to. Thanks – user2709885 May 07 '15 at 14:50