Go:用于映射的类型断言

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

Go: type assertion for maps

问题

我正在从JSON中读取数据结构。在这个过程中进行了一些转换,最后我得到了一个struct,其中一个字段的类型是interface{}。实际上,它是一个map,所以JSON将它放在了map[string]interface{}中。

我知道底层结构实际上是map[string]float64,我想要像这样使用它,所以我尝试进行断言。以下代码重现了这种行为:

  1. type T interface{}
  2. func jsonMap() T {
  3. result := map[string]interface{}{
  4. "test": 1.2,
  5. }
  6. return T(result)
  7. }
  8. func main() {
  9. res := jsonMap()
  10. myMap := res.(map[string]float64)
  11. fmt.Println(myMap)
  12. }

我得到了错误:

  1. panic: interface conversion: main.T is map[string]interface {}, not map[string]float64

我可以这样做:

  1. func main() {
  2. // 第一次断言
  3. res := jsonMap().(map[string]interface{})
  4. myMap := map[string]float64{
  5. "test": res["test"].(float64), // 第二次断言
  6. }
  7. fmt.Println(myMap)
  8. }

这样可以正常工作,但我觉得这样做很丑陋,因为我需要重建整个map并使用两次断言。有没有一种正确的方法来强制第一次断言丢弃interface{}并使用float64?换句话说,如何正确地进行原始断言.(map[string]float64)

编辑:

我解析的实际数据如下所示:

  1. [
  2. { "Type":"pos",
  3. "Content":{"x":0.5 , "y": 0.3}} ,
  4. { "Type":"vel",
  5. "Content":{"vx": 0.1, "vy": -0.2}}
  6. ]

在Go中,我使用structencoding/json进行如下操作:

  1. type data struct {
  2. Type string
  3. Content interface{}
  4. }
  5. // 从WebSocket连接中读取JSON
  6. _, event, _ := c.ws.ReadMessage()
  7. j := make([]data, 0)
  8. 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:

  1. type T interface{}
  2. func jsonMap() T {
  3. result := map[string]interface{}{
  4. "test": 1.2,
  5. }
  6. return T(result)
  7. }
  8. func main() {
  9. res := jsonMap()
  10. myMap := res.(map[string]float64)
  11. fmt.Println(myMap)
  12. }

I get the error:

  1. panic: interface conversion: main.T is map[string]interface {}, not map[string]float64

I can do the following:

  1. func main() {
  2. // A first assertion
  3. res := jsonMap().(map[string]interface{})
  4. myMap := map[string]float64{
  5. "test": res["test"].(float64), // A second assertion
  6. }
  7. fmt.Println(myMap)
  8. }

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:

  1. [
  2. {"Type":"pos",
  3. "Content":{"x":0.5 , y: 0.3}} ,
  4. {"Type":"vel",
  5. "Content":{"vx": 0.1, "vy": -0.2}}
  6. ]

In Go I use a struct and encoding/json in the following way.

  1. type data struct {
  2. Type string
  3. Content interface{}
  4. }
  5. // I read the JSON from a WebSocket connection
  6. _, event, _ := c.ws.ReadMessage()
  7. j := make([]data,0)
  8. json.Unmarshal(event, &j)

答案1

得分: 8

你不能将map[string]interface{}断言为map[string]float64。你需要手动创建一个新的映射。

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. )
  6. var exampleResponseData = `{
  7. "Data":[
  8. {
  9. "Type":"pos",
  10. "Content":{
  11. "x":0.5,
  12. "y":0.3
  13. }
  14. },
  15. {
  16. "Type":"vel",
  17. "Content":{
  18. "vx":0.1,
  19. "vy":-0.2
  20. }
  21. }
  22. ]
  23. }`
  24. type response struct {
  25. Data []struct {
  26. Type string
  27. Content interface{}
  28. }
  29. }
  30. func main() {
  31. var response response
  32. err := json.Unmarshal([]byte(exampleResponseData), &response)
  33. if err != nil {
  34. fmt.Println("无法处理无效的 JSON")
  35. }
  36. for i := 0; i < len(response.Data); i++ {
  37. response.Data[i].Content = convertMap(response.Data[i].Content)
  38. }
  39. }
  40. func convertMap(originalMap interface{}) map[string]float64 {
  41. convertedMap := map[string]float64{}
  42. for key, value := range originalMap.(map[string]interface{}) {
  43. convertedMap[key] = value.(float64)
  44. }
  45. return convertedMap
  46. }

你确定不能将Content定义为map[string]float64吗?请参考下面的示例。如果不能,你又如何知道首先可以将其转换为该类型?

  1. type response struct {
  2. Data []struct {
  3. Type string
  4. Content map[string]float64
  5. }
  6. }
  7. var response response
  8. err := json.Unmarshal([]byte(exampleResponseData), &response)
英文:

You cannot type assert map[string]interface{} to map[string]float64. You need to manually create new map.

  1. package main
  2. import (
  3. &quot;encoding/json&quot;
  4. &quot;fmt&quot;
  5. )
  6. var exampleResponseData = `{
  7. &quot;Data&quot;:[
  8. {
  9. &quot;Type&quot;:&quot;pos&quot;,
  10. &quot;Content&quot;:{
  11. &quot;x&quot;:0.5,
  12. &quot;y&quot;:0.3
  13. }
  14. },
  15. {
  16. &quot;Type&quot;:&quot;vel&quot;,
  17. &quot;Content&quot;:{
  18. &quot;vx&quot;:0.1,
  19. &quot;vy&quot;:-0.2
  20. }
  21. }
  22. ]
  23. }`
  24. type response struct {
  25. Data []struct {
  26. Type string
  27. Content interface{}
  28. }
  29. }
  30. func main() {
  31. var response response
  32. err := json.Unmarshal([]byte(exampleResponseData), &amp;response)
  33. if err != nil {
  34. fmt.Println(&quot;Cannot process not valid json&quot;)
  35. }
  36. for i := 0; i &lt; len(response.Data); i++ {
  37. response.Data[i].Content = convertMap(response.Data[i].Content)
  38. }
  39. }
  40. func convertMap(originalMap interface{}) map[string]float64 {
  41. convertedMap := map[string]float64{}
  42. for key, value := range originalMap.(map[string]interface{}) {
  43. convertedMap[key] = value.(float64)
  44. }
  45. return convertedMap
  46. }

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?

  1. type response struct {
  2. Data []struct {
  3. Type string
  4. Content map[string]float64
  5. }
  6. }
  7. var response response
  8. err := json.Unmarshal([]byte(exampleResponseData), &amp;response)

huangapple
  • 本文由 发表于 2016年3月1日 02:10:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/35706501.html
匿名

发表评论

匿名网友

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

确定