嵌套结构的属性,其属性名未知?

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

Nested properties for structs with unknown property names?

问题

我正在使用JSON从外部源获取一些值,并将其放入变量中。

我有一个像这样的类型,json.Unmarshal将值放入其中:

	type Frame struct {
		Type  string
		Value map[string]interface{}
	}

	var data Frame

解码后,我可以通过data.Type访问类型

但是,如果我尝试这样做:

	if data.Type == "image" {
		fmt.Printf("%s\n", data.Value.Imagedata)
	}

编译器会报错,说没有data.Value.Imagedata这样的值。

所以我的问题是,如何在Go中引用我知道根据某些条件将存在的属性?

这样做是可以的:

	type Image struct {
		Filename string
	}

	type Frame struct {
		Type  string
		Value map[string]interface{}
	}

但是这并不是很灵活,因为我将会接收到不同的Value

英文:

I'm using JSON to get some values into a variable from an external source.

I have a type like this that json.Unmarshal puts values into:

	type Frame struct {
		Type  string
		Value map[string]interface{}
	}

	var data Frame

After unmarshal, I can access a the type by: data.Type

but if I try doing something like:

	if data.Type == "image" {
		fmt.Printf("%s\n", data.Value.Imagedata)
	}

The compiler complains about no such value data.Value.Imagedata.

So my question is, how do I reference properties in Go that I know will be there depending on some condition?

Doing this works:

	type Image struct {
		Filename string
	}

	type Frame struct {
		Type  string
		Value map[string]interface{}
	}

But that isn't very flexible as I will be receiving different Values.

答案1

得分: 15

json.Unmarshal将尽力将数据放置在与您的类型最匹配的位置。从技术上讲,您的第一个示例将起作用,但是您正在尝试使用点表示法访问Value字段,即使您声明它是一个映射:

这应该给您一些输出形式:

if data.Type == 'image'{
    fmt.Printf("%v\n", data.Value["Imagedata"])
}

...假设"Imagedata"是JSON中的一个键。

您可以选择根据您希望的结构的深度来定义类型,或者使用interface{},然后对值进行类型断言。由于Value字段是一个映射,您总是可以像Value[key]这样访问键,并且该映射条目的值是一个interface{},您可以像Value[key].(float64)这样进行类型断言。

至于更明确的结构,我发现您可以将对象分解为它们自己的类型,或者在一个地方嵌套定义它:

嵌套(使用匿名结构)

type Frame struct {
	Type  string
	Value struct {
		Imagedata string `json:"image_data"`
	}
}

单独的结构

type Frame struct {
	Type    string
	Value   value 
}

type value struct {
	Imagedata string `json:"image_data"`
}

我自己还在学习Go,所以这是我目前理解的范围。

英文:

json.Unmarshal will do its best to place the data where it best aligns with your type. Technically your first example will work, but you are trying to access the Value field with dot notation, even though you declared it to be a map:

This should give you some form of output:

if data.Type == 'image'{
    fmt.Printf("%v\n", data.Value["Imagedata"])
}

… considering that "Imagedata" was a key in the JSON.

You have the option of defining the type as deeply as you want or expect the structure to be, or using an interface{} and then doing type assertions on the values. With the Value field being a map, you would always access the keys like Value[key], and the value of that map entry is an interface{} which you could type assert like Value[key].(float64).

As for doing more explicit structures, I have found that you could either break up the objects into their own types, or define it nested in one place:

Nested (with anonymous struct)

type Frame struct {
	Type  string
	Value struct {
		Imagedata string `json:"image_data"`
	}
}

Seperate structs

type Frame struct {
	Type    string
	Value   value 
}

type value struct {
	Imagedata string `json:"image_data"`
}

I'm still learning Go myself, so this the extent of my current understanding :-).

huangapple
  • 本文由 发表于 2012年3月21日 16:54:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/9801312.html
匿名

发表评论

匿名网友

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

确定