英文:
Go: type assertion for maps
问题
我正在从JSON中读取数据结构。在这个过程中进行了一些转换,最后我得到了一个struct
,其中一个字段的类型是interface{}
。实际上,它是一个map,所以JSON将它放在了map[string]interface{}
中。
我知道底层结构实际上是map[string]float64
,我想要像这样使用它,所以我尝试进行断言。以下代码重现了这种行为:
type T interface{}
func jsonMap() T {
result := map[string]interface{}{
"test": 1.2,
}
return T(result)
}
func main() {
res := jsonMap()
myMap := res.(map[string]float64)
fmt.Println(myMap)
}
我得到了错误:
panic: interface conversion: main.T is map[string]interface {}, not map[string]float64
我可以这样做:
func main() {
// 第一次断言
res := jsonMap().(map[string]interface{})
myMap := map[string]float64{
"test": res["test"].(float64), // 第二次断言
}
fmt.Println(myMap)
}
这样可以正常工作,但我觉得这样做很丑陋,因为我需要重建整个map并使用两次断言。有没有一种正确的方法来强制第一次断言丢弃interface{}
并使用float64
?换句话说,如何正确地进行原始断言.(map[string]float64)
?
编辑:
我解析的实际数据如下所示:
[
{ "Type":"pos",
"Content":{"x":0.5 , "y": 0.3}} ,
{ "Type":"vel",
"Content":{"vx": 0.1, "vy": -0.2}}
]
在Go中,我使用struct
和encoding/json
进行如下操作:
type data struct {
Type string
Content interface{}
}
// 从WebSocket连接中读取JSON
_, event, _ := c.ws.ReadMessage()
j := make([]data, 0)
json.Unmarshal(event, &j)
英文:
I'm reading data structures from JSON. There's a little bit of conversions going on and at the end I have a struct
where one of the fields is of type interface{}
. It's actually a map, so JSON puts it inside a map[string]inteface{}
.
I actually know that the underlying structure is map[string]float64
and I would like to use it like that, so I try to do an assertion. The following code reproduces the behaviour:
type T interface{}
func jsonMap() T {
result := map[string]interface{}{
"test": 1.2,
}
return T(result)
}
func main() {
res := jsonMap()
myMap := res.(map[string]float64)
fmt.Println(myMap)
}
I get the error:
panic: interface conversion: main.T is map[string]interface {}, not map[string]float64
I can do the following:
func main() {
// A first assertion
res := jsonMap().(map[string]interface{})
myMap := map[string]float64{
"test": res["test"].(float64), // A second assertion
}
fmt.Println(myMap)
}
This works fine, but I find it very ugly since I need to reconstruct the whole map and use two assertions. Is there a correct way to force the first assertion to drop the interface{}
and use float64
? In other words, what is the correct way to do the original assertion .(map[string]float64)
?
Edit:
The actual data I'm parsing looks like this:
[
{"Type":"pos",
"Content":{"x":0.5 , y: 0.3}} ,
{"Type":"vel",
"Content":{"vx": 0.1, "vy": -0.2}}
]
In Go I use a struct
and encoding/json
in the following way.
type data struct {
Type string
Content interface{}
}
// I read the JSON from a WebSocket connection
_, event, _ := c.ws.ReadMessage()
j := make([]data,0)
json.Unmarshal(event, &j)
答案1
得分: 8
你不能将map[string]interface{}
断言为map[string]float64
。你需要手动创建一个新的映射。
package main
import (
"encoding/json"
"fmt"
)
var exampleResponseData = `{
"Data":[
{
"Type":"pos",
"Content":{
"x":0.5,
"y":0.3
}
},
{
"Type":"vel",
"Content":{
"vx":0.1,
"vy":-0.2
}
}
]
}`
type response struct {
Data []struct {
Type string
Content interface{}
}
}
func main() {
var response response
err := json.Unmarshal([]byte(exampleResponseData), &response)
if err != nil {
fmt.Println("无法处理无效的 JSON")
}
for i := 0; i < len(response.Data); i++ {
response.Data[i].Content = convertMap(response.Data[i].Content)
}
}
func convertMap(originalMap interface{}) map[string]float64 {
convertedMap := map[string]float64{}
for key, value := range originalMap.(map[string]interface{}) {
convertedMap[key] = value.(float64)
}
return convertedMap
}
你确定不能将Content
定义为map[string]float64
吗?请参考下面的示例。如果不能,你又如何知道首先可以将其转换为该类型?
type response struct {
Data []struct {
Type string
Content map[string]float64
}
}
var response response
err := json.Unmarshal([]byte(exampleResponseData), &response)
英文:
You cannot type assert map[string]interface{}
to map[string]float64
. You need to manually create new map.
package main
import (
"encoding/json"
"fmt"
)
var exampleResponseData = `{
"Data":[
{
"Type":"pos",
"Content":{
"x":0.5,
"y":0.3
}
},
{
"Type":"vel",
"Content":{
"vx":0.1,
"vy":-0.2
}
}
]
}`
type response struct {
Data []struct {
Type string
Content interface{}
}
}
func main() {
var response response
err := json.Unmarshal([]byte(exampleResponseData), &response)
if err != nil {
fmt.Println("Cannot process not valid json")
}
for i := 0; i < len(response.Data); i++ {
response.Data[i].Content = convertMap(response.Data[i].Content)
}
}
func convertMap(originalMap interface{}) map[string]float64 {
convertedMap := map[string]float64{}
for key, value := range originalMap.(map[string]interface{}) {
convertedMap[key] = value.(float64)
}
return convertedMap
}
Are you sure you cannot define Content
as map[string]float64
? See example below. If not, how can you know that you can cast it in the first place?
type response struct {
Data []struct {
Type string
Content map[string]float64
}
}
var response response
err := json.Unmarshal([]byte(exampleResponseData), &response)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论