解组为接口类型

时间:2016-03-18 16:37:50

标签: json go unmarshalling

我希望下面的代码能够打印struct J类型的对象,但是它会打印一个类型为map[string]interface{}的地图对象。我可以理解为什么它会像那样,但是当我运行时,反射.ValueOf(i).Kind(),它返回Struct,所以它有点让我觉得Unmarshal方法应该返回类型J代替地图。谁能开导我?

type J struct {
    Text string
}

func main() {
    j := J{}
    var i interface{} = j

    js := "{\"Text\": \"lala\"}"


    json.Unmarshal([]byte(js), &i)

    fmt.Printf("%#v", i)

}

2 个答案:

答案 0 :(得分:3)

您传入Unmarshal的类型不是*J,而是传递给*interface{}

json包反映它收到的指针的类型时,它会看到interface{},因此它会使用默认类型的包进行解组,这是

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

几乎没有理由使用指向接口的指针。如果您发现自己使用指向界面的指针,并且您不知道完全为什么,那么它可能是一个错误。如果要解组为J,请直接传入。{1}}。如果需要将其分配给中间接口,请确保使用指向原始值的指针,而不是指向其接口的指针。

http://play.golang.org/p/uJDFKfSIxN

j := J{}
var i interface{} = &j

js := "{\"Text\": \"lala\"}"

json.Unmarshal([]byte(js), i)

fmt.Printf("%#v", i)

答案 1 :(得分:2)

这是预期的行为:不是给json.Unmarshal指向内存中正确类型的位置的指针,而是给它一个指向内存中类型为interface{}的位置的指针。它本质上可以在JSON定义的类型下存储任何内容,因此它就是这样。

这样看:

  1. Unmarshal可以存储类型v
  2. 的数据interface{}
  3. Unmarshal检测到编码为JSON
  4. 的地图
  5. Unmarshal发现目标类型属于interface{}类型,从中创建了一个go map并将其存储在v
  6. 如果你给它的类型不同于interface{},那么这个过程会是这样的:

    1. Unmarshal可以存储类型v
    2. 的数据struct main.J
    3. Unmarshal检测到编码为JSON
    4. 的地图
    5. Unmarshal看到目标类型为struct main.J并开始递归地将数据拟合到类型
    6. 重点是,初始分配

      var i interface{} = j
      

      完全被json.Unmarshal忽略。