Golang中如何解析JSON数据

Golang中如何解析JSON数据 我正在尝试理解 interface{}&interface{} 之间的区别。我搞不清楚为什么在第一个代码片段中,反序列化是在 Map 数据类型中完成的,而在第二个片段中,反序列化是在 struct 数据类型中完成的。

案例 1:

package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name string `json:"name"`
}

func Decode(p interface{}) {
	str := `
        {"name" : "aryan"}
    `
	json.Unmarshal([]byte(str), &p)
	fmt.Printf("%+v \n", p)
}

func main() {
	p := Person{}
	Decode(p)
	fmt.Printf("%+v \n", p)
}

输出

map[name:aryan] 
{Name:} 

案例 2:

package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name string `json:"name"`
}

func Decode(p interface{}) {
	str := `
        {"name" : "aryan"}
    `
	json.Unmarshal([]byte(str), &p)
	fmt.Printf("%+v \n", p)
}

func main() {
	p := &Person{}
	Decode(p)
	fmt.Printf("%+v \n", p)
}

输出

&{Name:aryan} 
&{Name:aryan} 

我对案例 1、3 和 4 很清楚。但在这里的案例 2 中,我们将地址传递给了接口值,然后在反序列化时再次传递了该指针的地址。那么,反序列化是如何处理指向指针的指针的呢?

案例 3:

package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name string `json:"name"`
}

func Decode(p interface{}) {
	str := `
        {"name" : "aryan"}
    `
	json.Unmarshal([]byte(str), p)
	fmt.Printf("%+v \n", p)
}

func main() {
	p := &Person{}
	Decode(p)
	fmt.Printf("%+v \n", p)
}

输出

&{Name:aryan} 
&{Name:aryan} 

案例 4:

package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name string `json:"name"`
}

func Decode(p interface{}) {
	str := `
        {"name" : "aryan"}
    `
	json.Unmarshal([]byte(str), p)
	fmt.Printf("%+v \n", p)
}

func main() {
	p := Person{}
	Decode(p)
	fmt.Printf("%+v \n", p)
}

输出

{Name:} 
{Name:}  

更多关于Golang中如何解析JSON数据的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

你好 @aryanmaurya1

Decode() 函数的参数是一个接口类型,但在调用 Decode(p) 时,实际参数 p 是一个指向 Person 的指针。

你可以在 Decode() 内部打印 p 的类型来确认这一点:

	json.Unmarshal([]byte(str), &p)
	fmt.Printf("%T \n", p)  // T 代表 "type"

输出:

*main.Person

更多关于Golang中如何解析JSON数据的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在案例2中,json.Unmarshal([]byte(str), &p) 确实传递了指向接口值的指针,这形成了双重指针。让我们分析具体的工作原理:

func main() {
    p := &Person{}  // p 是 *Person 类型
    Decode(p)       // p 作为 interface{} 传递
}

func Decode(p interface{}) {
    // 此时 p 是一个接口值,包含:
    // - 类型: *Person
    // - 值: 指向 Person 结构体的指针
    
    // &p 获取的是接口变量本身的地址
    // 这相当于 **Person(指向指针的指针)
    json.Unmarshal([]byte(str), &p)
}

json.Unmarshal 能够正确处理这种情况,因为当它接收到 &p(接口变量的地址)时:

  1. 类型检查Unmarshal 检查发现参数是 *interface{} 类型
  2. 解引用:它会解引用一次,得到 interface{}
  3. 反射处理:通过反射发现接口值中存储的是 *Person 类型
  4. 最终目标:继续解引用,将数据写入实际的 Person 结构体

验证示例:

package main

import (
    "encoding/json"
    "fmt"
    "reflect"
)

type Person struct {
    Name string `json:"name"`
}

func Decode(p interface{}) {
    str := `{"name" : "aryan"}`
    
    fmt.Printf("p 的类型: %v\n", reflect.TypeOf(p))
    fmt.Printf("&p 的类型: %v\n", reflect.TypeOf(&p))
    
    json.Unmarshal([]byte(str), &p)
    fmt.Printf("Decode 内部: %+v\n", p)
}

func main() {
    p := &Person{}
    fmt.Printf("main 中 p 的类型: %T\n", p)
    
    Decode(p)
    fmt.Printf("main 中 p 的值: %+v\n", p)
}

输出:

main 中 p 的类型: *main.Person
p 的类型: *main.Person
&p 的类型: *interface {}
Decode 内部: &{Name:aryan}
main 中 p 的值: &{Name:aryan}

关键点:

  • json.Unmarshal 的第二个参数必须是目标值的指针
  • 当传递 &p 时,Unmarshal 通过反射能够正确处理多重指针
  • 最终数据会正确写入原始的 Person 结构体

这种设计允许 Unmarshal 处理各种复杂情况,包括接口类型和多重指针。

回到顶部