我想编写一个模拟数据方法,该方法可以接受几种类型的参数并根据其json数据返回对应的对象。代码如下:
func MockData(jsonPath string,v interface{})(interface{},error){
var ret interface{}
data,_ := ioutil.ReadFile(jsonPath)
switch v.(type) {
case Req:
ret = Req{}
fmt.Printf("\n===before Unmarshal==%T===\n",ret)
err = json.Unmarshal(data,&ret)
if err!=nil{...}
fmt.Printf("======after unmarshal===%T\n",ret)
case ...
default:
fmt.Printf("error===not match")
}
return ret,err
}
但是,当我使用它时会惊慌。代码如下:
func main(){
reqJsonPath := /xx/yy/req.json
obj,err:=test.MockData(jsonFile,Req{})
if err!=nil{...}
require := obj.(Req) //panic cant []interface{} to Req
}
并且MockData的输出是:
===before Unmarshal==Req===
======after unmarshal===[]interface{}
解组后更改的对象类型 。更奇怪的是,如果我替换:
ret = Req{}
与
ret = &Req{}
输出将与以下相同:
===before Unmarshal==*Req===
======after unmarshal===*Req
为了更方便地重现该问题,我给出了Require结构,如下所示:
type Req []*Ele
type Ele struct {
ID int
Level int
}
摘要:
答案 0 :(得分:1)
我能否实现根据其json和类型生成不同类型对象的预期功能?
func MockData(filename string, v interface{}) (interface{}, error) {
data, _ := ioutil.ReadFile(filename)
switch t := v.(type) {
case Req:
// t at this point is a Req{}
err := json.Unmarshal(data, &t)
return t, err
}
return nil, errors.New("unknown type")
}
我真的不了解您的动机,为什么您需要传递实际的结构而不是指针。 Check this demonstration
为什么解组后对象的类型会发生变化,为什么在添加&后它不会发生变化?
使用&ret
(其中ret
是接口)进行解组时,您将获取该接口的地址。因此,json.Unmarshal()
将看到支持数据是接口而不是结构的指针。 json.Unmarshal()
将使用的默认数据类型是map[string]interface{}
用于对象,[]interface{}
用于数组。
现在,如果您使用ret
为ret
的{{1}}解组,&Req{}
将检查后备数据是否为json.Unmarshal()
,因此可以做到这一点使用该结构的字段取消编组。
修改:
您似乎被指向接口的指针所迷惑,与具有指针的接口不同。尝试使用此代码,您将看到区别。
struct
请记住,接口只是普通值,它们也占用内存。现在,如果您获取该内存的地址,则将获得指向接口的指针,而不是指向该接口所引用的数据的指针。
答案 1 :(得分:0)
是的,但是您必须在调用端使用类型声明将其转换回去,即
MyFoo:=MockData("foo.json", Foo{}).(Foo)
(或功能中有多个return ret.(Foo)
return ret.(Bar)
)
Unmarshal源代码的顶部有一些有用的评论 即
// To unmarshal JSON into a pointer, Unmarshal first handles the case of
// the JSON being the JSON literal null. In that case, Unmarshal sets
// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into
// the value pointed at by the pointer. If the pointer is nil, Unmarshal
// allocates a new value for it to point to.
和
// 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
因此,在第一种情况下,您需要解组为接口值(ret
被声明为接口{})
在第二种情况下,有一个指向结构的指针,所以您可以得到