Why would adding a func in an interface cause json.Unmarshal to fail?

时间:2018-03-23 00:24:13

标签: json go

Why does this fail with the error :

json: cannot unmarshal object into Go struct field Person.spouse of type main.Spouse

type Spouse interface {
    Name() // Adding this causes an error
}

type Address interface {
}

type Person struct {
    Name string   `json:"name"`
    A    *Address `json:"address"`
    S    *Spouse  `json:"spouse"`
}

func main() {
    b := []byte(`{
     "name":"sarah", 
     "address":{
         "street":"101 main" 
         }, 
     "spouse":{
         "name":"joe"
         }
     }
    `)

    p := &Person{}
    if err := json.Unmarshal(b, p); err != nil {
        fmt.Printf("%s", err)
    }
}

Looking at the docs, I don't see why adding a function in an interface would cause an error. I was expecting json.Unmarshal to simply ignore the Name() function since it's not part of the list processed by json.Unmarshal.

Here is the code in go playground.

go version go1.10 darwin/amd64

2 个答案:

答案 0 :(得分:4)

来自fine manual

  

func Unmarshal
  [...]
  要将JSON解组为接口值,Unmarshal将其中一个存储在接口值中:

bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null

您正在尝试将JSON对象解组为接口,因此该接口背后的值将是map[string]interface{}来表示键/值对。但map[string]interface{}没有Name()方法,因此它不会实现您的Spouse界面。

如果我们稍微简化您的示例并摆脱Name()方法,我们可以看到正在发生的事情:

type Spouse interface {
}

type Person struct {
    S *Spouse `json:"spouse"`
}

func main() {
    b := []byte(`{"spouse":{ "name":"joe" } }`)

    p := &Person{}
    if err := json.Unmarshal(b, p); err != nil {
        fmt.Printf("%s", err)
    }
    spouse := (*p.S).(map[string]interface{})
    fmt.Printf("%+v\n", spouse)
}

spouse是记录的map[string]interface{}

答案 1 :(得分:1)

问题在于您尝试使用不匹配的特定数据类型映射json中spouse的值。正如this article中所报告的那样,json使用空接口将通用数据类型映射到文件中使用的正确数据类型。

  

json包使用map[string]interface{}[]interface{}值   存储任意JSON对象和数组;它会愉快地解散   任何有效的JSON blob到普通interface{}值。默认   具体的Go类型是:

     
      
  • bool用于JSON布尔值,
  •   
  • float64表示JSON号码,
  •   
  • string表示JSON字符串,
  •   
  • nil表示JSON为null。
  •   

如果您想从另一个角度看它,这意味着您不能使用除这些数据类型之外的任何内容来映射JSON中的数据。您的非空界面不是有效类型。