json - json.Unmarshal 接口指针,带有后面的类型断言
问题描述
因为我经常解http.Response.Body
组,我想我可以编写一个函数来处理读取、关闭和解组到各种不同结构的所有麻烦。这就是为什么我引入了一个函数func unmarhalInterface(closer *io.ReadCloser, v *interface{}) error
,然后可以用t:=i.(T)
.
根据这个答案,我已经将它包装成一个类型的值*interface{}
,但是因为覆盖类型是interface{}
而不是myStruct
,所以json
包实现选择了map[string]interface{}
。之后类型断言失败(当然)。有什么我遗漏的或者需要这个实现“手动”的类型断言,这意味着查找地图中的所有字段并将我想要的那些分配到我的结构中。
下面的代码在注释中包含带有符号的最小示例。如果我的解释不够充分,请询问。
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
)
type myStruct struct {
A string `json:"a"`
B string `json:"b"`
}
func main() {
jsonBlob := []byte(`{"a":"test","b":"test2"}`)
var foo = interface{}(myStruct{})
closer := ioutil.NopCloser(bytes.NewReader(jsonBlob))
err := unmarshalCloser(&closer, &foo)
if err != nil {
log.Fatal(err)
}
fmt.Println(fmt.Sprintf("%v", foo))
// That´s what i want:
foo2 := foo.(myStruct)
fmt.Println(foo2.A)
}
func unmarshalCloser(closer *io.ReadCloser, v *interface{}) error {
defer func() { _ = (*closer).Close() }()
data, err := ioutil.ReadAll(*closer)
if err != nil {
return err
}
err = json.Unmarshal(data, v)
if err != nil {
return err
}
return nil
}
解决方案
空接口不是实际类型,它基本上可以匹配任何东西。如评论中所述,指向空接口的指针实际上没有意义,因为指针已经与空接口匹配,因为所有内容都与空接口匹配。为了使您的代码正常工作,您应该删除结构周围的接口包装器,因为这只会弄乱 json 类型检查,而空接口的全部意义在于您可以将任何东西传递给它。
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
)
type myStruct struct {
A string `json:"a"`
B string `json:"b"`
}
func main() {
jsonBlob := []byte(`{"a":"test","b":"test2"}`)
var foo = &myStruct{} // This need to be a pointer so its attributes can be assigned
closer := ioutil.NopCloser(bytes.NewReader(jsonBlob))
err := unmarshalCloser(closer, foo)
if err != nil {
log.Fatal(err)
}
fmt.Println(fmt.Sprintf("%v", foo))
// That´s what i want:
fmt.Println(foo.A)
}
// You don't need to declare either of these arguments as pointers since they're both interfaces
func unmarshalCloser(closer io.ReadCloser, v interface{}) error {
defer closer.Close()
// v NEEDS to be a pointer or the json stuff will barf
// Simplified with the decoder
return json.NewDecoder(closer).Decode(v)
}
推荐阅读
- algorithm - 证明对 TREE-SUCCESSOR 的 k 次连续调用需要 O(k + h) 时间
- android - 夜间模式下 RecyclerView 的问题 android kotlin NullPointerException
- javascript - 在加载 html 文档之前搜索元素并显示符合条件的页面
- java - Google OR-Tools:所有路线组合的总时间容量
- python - 有没有一种方法可以在不使用 Python 循环的情况下根据先前的行获取新的列值?
- python-3.x - 如何从另一个以类对象为参数的python脚本调用python脚本等待它完成
- chisel - IO 连接 Vec 异常
- c# - 如何在 Visual Studio 2019 C# 中运行单独的文件
- c# - 是否可以从 Stream 创建 AssemblyName 实例?
- ios - 使用 XCUITest 框架访问表盘