使用 json 解码转换接口
Converting interfaces with json decoding
考虑以下代码:
package main
import (
"fmt"
"encoding/json"
)
func testNoPointer() interface{} {
return []int{}
}
func testPointer() interface{} {
return &[]int{}
}
func main() {
jsonString := "[1]"
noPointer := testNoPointer()
fmt.Printf("%T\n", noPointer)
err := json.Unmarshal([]byte(jsonString), &noPointer)
if (err == nil) {
fmt.Printf("%T\n", noPointer)
}
pointer := testPointer()
err2 := json.Unmarshal([]byte(jsonString), &pointer)
if (err2 == nil) {
fmt.Printf("%T\n", pointer)
}
}
它输出:
[]int
[]interface {}
*[]int
为什么解组会删除值的类型信息?结果这个 decoded := noPointer.([]int)
将抛出 interface conversion: interface {} is []interface {}, not []int
。是否可以将其转换为正确的类型?
您的 testNoPointer()
和 testPointer()
函数 return interface{}
值。请理解,一旦将某些内容放入(包装)接口值中,就无法再对其进行修改。
所以在第一种情况下,您有一个包装切片的接口值。您不能将元素添加到包装的切片中,因为这需要修改切片 header(例如它的长度字段),因此在第一种情况下解组不能使用您传递的值进行解组。它必须创造新的价值。由于您要解组为 interface{}
值(noPointer
的类型是 interface{}
),encoding/json
包可以自由选择它认为适合解组的任何类型,并且json.Unmarshal()
记录:
To unmarshal JSON into an interface value, Unmarshal stores one of these in the interface value:
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 数组,因此它选择 []interface{}
。
在您的第二个示例中,您将 *int[]
包装在接口值中。确实不能修改包装在接口中的值,但这不是必须发生的。 encoding/json
包可以只修改pointed值,所以接口中的包裹指针可以保持不变,所以encoding/json
包可以使用指针,因此可以保留元素类型。
请注意,在第二个示例中,包装指针不是 nil
很重要,因为如果它是 nil
,则 encoding/json
包无法使用接口值包装指针:一个 nil
指针指向任何地方,因此必须分配一个新的指针。但是话又说回来,我们又到了 encoding/json
解组为 interface{}
值(pointer
的类型是 interface{}
),所以 encoding/json
包将恢复为要解组的 JSON 数组创建 []interface{}
。
当 testPointer2()
return 是一个 nil
指针包装时,您可以测试它:
func testPointer2() interface{} {
var x *[]int
return x // this will be a nil pointer
}
并对其进行测试:
pointer2 := testPointer2()
err3 := json.Unmarshal([]byte(jsonString), &pointer2)
if err3 == nil {
fmt.Printf("%T\n", pointer2)
}
哪些输出(在 Go Playground 上尝试):
[]interface {}
我们再次“丢失”了类型信息,因为无法使用包含 nil
指针的接口值。
参见 github 上的相关问题/讨论:encoding/json: clarify what happens when unmarshaling into a non-empty interface{} #26946
考虑以下代码:
package main
import (
"fmt"
"encoding/json"
)
func testNoPointer() interface{} {
return []int{}
}
func testPointer() interface{} {
return &[]int{}
}
func main() {
jsonString := "[1]"
noPointer := testNoPointer()
fmt.Printf("%T\n", noPointer)
err := json.Unmarshal([]byte(jsonString), &noPointer)
if (err == nil) {
fmt.Printf("%T\n", noPointer)
}
pointer := testPointer()
err2 := json.Unmarshal([]byte(jsonString), &pointer)
if (err2 == nil) {
fmt.Printf("%T\n", pointer)
}
}
它输出:
[]int
[]interface {}
*[]int
为什么解组会删除值的类型信息?结果这个 decoded := noPointer.([]int)
将抛出 interface conversion: interface {} is []interface {}, not []int
。是否可以将其转换为正确的类型?
您的 testNoPointer()
和 testPointer()
函数 return interface{}
值。请理解,一旦将某些内容放入(包装)接口值中,就无法再对其进行修改。
所以在第一种情况下,您有一个包装切片的接口值。您不能将元素添加到包装的切片中,因为这需要修改切片 header(例如它的长度字段),因此在第一种情况下解组不能使用您传递的值进行解组。它必须创造新的价值。由于您要解组为 interface{}
值(noPointer
的类型是 interface{}
),encoding/json
包可以自由选择它认为适合解组的任何类型,并且json.Unmarshal()
记录:
To unmarshal JSON into an interface value, Unmarshal stores one of these in the interface value:
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 数组,因此它选择 []interface{}
。
在您的第二个示例中,您将 *int[]
包装在接口值中。确实不能修改包装在接口中的值,但这不是必须发生的。 encoding/json
包可以只修改pointed值,所以接口中的包裹指针可以保持不变,所以encoding/json
包可以使用指针,因此可以保留元素类型。
请注意,在第二个示例中,包装指针不是 nil
很重要,因为如果它是 nil
,则 encoding/json
包无法使用接口值包装指针:一个 nil
指针指向任何地方,因此必须分配一个新的指针。但是话又说回来,我们又到了 encoding/json
解组为 interface{}
值(pointer
的类型是 interface{}
),所以 encoding/json
包将恢复为要解组的 JSON 数组创建 []interface{}
。
当 testPointer2()
return 是一个 nil
指针包装时,您可以测试它:
func testPointer2() interface{} {
var x *[]int
return x // this will be a nil pointer
}
并对其进行测试:
pointer2 := testPointer2()
err3 := json.Unmarshal([]byte(jsonString), &pointer2)
if err3 == nil {
fmt.Printf("%T\n", pointer2)
}
哪些输出(在 Go Playground 上尝试):
[]interface {}
我们再次“丢失”了类型信息,因为无法使用包含 nil
指针的接口值。
参见 github 上的相关问题/讨论:encoding/json: clarify what happens when unmarshaling into a non-empty interface{} #26946