如何在Go中初始化嵌套结构体?

huangapple go评论85阅读模式
英文:

How to initialise nested structs in go?

问题

你好,我很新手Golang,请帮助我。我在一个结构体内定义了一个结构体。但是当我尝试初始化主结构体时,出现了错误。

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"]}

我得到的错误是:无法将类型interface {}用作字段值中的struct类型:需要类型断言。

请建议一种初始化DetailsFilter的方法。
我尝试了在https://stackoverflow.com/questions/24809235/initialize-a-nested-struct-in-golang中描述的方法,但这种方法也不起作用。

英文:

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 https://stackoverflow.com/questions/24809235/initialize-a-nested-struct-in-golang, but even this is not working.

答案1

得分: 6

很抱歉,如果结构体字段的类型是匿名结构体,在构造时只能通过“复制”匿名结构体类型(再次指定它)来进行初始化:

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

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

输出结果:

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

更简洁的替代方案

因此,我建议不要在构造时进行初始化,而是在创建了零值结构体之后进行初始化,像这样:

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

输出结果:

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

Go Playground上尝试一下。

给匿名结构体类型命名

或者根本不要使用匿名结构体作为字段类型,像这样为它命名:

type Filter struct {
    Name string
    ID   int
}

type DetailsFilter struct {
    Filter Filter
}

然后你可以简单地这样初始化它

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

输出结果(在Go Playground上尝试一下):

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

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}}

答案2

得分: 0

M["Filter"]的类型对于编译器来说是interface{},对于运行时来说是map[string]interface{}。这两者都无法转换为你的匿名结构体类型的Filter字段。

你应该为过滤器定义一个类型,或者干脆不使用它。为什么不这样做:

type DetailsFilter struct {
   Name    string        
   ID      int                           
} 

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

我不确定为什么你需要嵌套的匿名结构体。通常情况下,除非你真的需要,否则不需要使用interface{}。这通常意味着你正在与类型系统作斗争,而不是接受它。

你不应该像那样使用匿名结构体的原因是没有清晰的初始化方式。你有两个选项:

  1. 在结构体字面量中重复类型定义:
x := DetailsFilter{Filter: struct {
	Name string
	ID   int
}{Name: "Foo", ID: 5}}
  1. 设置单个字段:
x := DetailsFilter{}
x.Filter.Name = "Foo"
x.Filter.ID = 5

如果你想使用结构体字面量创建它们,似乎更容易创建一个真正的类型来表示嵌套字段。

英文:

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.

huangapple
  • 本文由 发表于 2015年5月7日 21:43:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/30102932.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定