什么是`reflect.ValueOf(& x).Elem`和`reflect.ValueOf(x)`之间的区别是什么?

时间:2018-03-15 06:28:06

标签: go reflection

在我看来,reflect.ValueOf(&x).Elem()等于reflect.ValueOf(x),因为.Elem()获取reflect.Value包含的指针的实际值。代码来了,json.Marshal的编码结果不同:

func generateRequest(input string, flag bool) interface{} {
    val := Node {
        Cmd: "Netware",
        Name: input,
    }
    if flag {
        return &val
    } else {
        return val
    }
}

func main() {
    request1 := generateRequest("123", true)
    request2 := generateRequest("123", false)

    request1Val := reflect.ValueOf(request1).Elem()
    fmt.Println(request1Val, request2)

    json1, err := json.Marshal(request1Val)
    checkErr(err)
    json2, err := json.Marshal(request2)
    checkErr(err)

    fmt.Println(json1, string(json1))
    fmt.Println(json2, string(json2))
    fmt.Println(reflect.DeepEqual(json1, json2))
}

下面是输出:

{Netware 123} {Netware 123}
[123 34 102 108 97 103 34 58 52 48 57 125] {"flag":409}
[123 34 99 109 100 34 58 34 78 101 116 119 97 114 101 34 44 34 110 97 109 101 34 58 34 49 50 51 34 125] {"cmd":"Netware","name":"123"}
false

我想知道为什么它们不同,以及如何修改我的代码以使request1的编码结果与request2相同。

1 个答案:

答案 0 :(得分:2)

对不起,这完全是错的。反射和JSON编组不会一起使用。

json2, err := json.Marshal(request2)部分是合理的:request2Node(包含在interface{}中,这里的事实并不有趣)。因此,callong json.Marshal会在Node封送{"cmd":"Netware","name":"123"},这就是你所期望的结果。

现在json1, err := json.Marshal(request1Val):Go 静态 键入,而您的request1Val类型为reflect.Value,这是一个完整的普通类型像stringtype myFoo struct {whatever}一样。如果您将此类型的内容传递给json.Marshal,您将获得reflect.Value的JSON序列化。不幸的是,这种序列化在任何方面都是完全无用的,因为它与reflect.Value中封装的值没有任何共同之处。想想reflect.Values是一个包含你的request1的不透明容器。不幸的是,它是不透明的,序列化不会神奇地揭示它隐藏的内容。

如果你想从reflect.Value转到它实际拥有的东西,可以使用Interface()方法来“解开”容器,然后取回你在reflect.Value中包装的内容。

你的问题与反映的无关.ValueOf(& x).Elem()或reflect.Value(x)的确有(不)不同。你的问题源于将一个reflect.Value传递给json.Marshal,它将从不工作,无论reflect.Value实际上是什么。