55

Go json unmarshal interface{} field bind to struct

 4 years ago
source link: https://www.tuicool.com/articles/qyAN7zR
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

写代码时碰到这么一个需求,某个字段根据不同条件对应不同子结构体,通过interface返给前端,同时前端上传时也要通过这个字段将数据传给后端。

struct -> json这个比较好办,给interface赋值不同的子结构体即可。json -> struct时有点难搞,需要做下特殊处理。默认情况json字符串解析到interface field会是mapstring。

先上代码:

type Foo struct {
    Type   string      `json:"type"`
    Object interface{} `json:"object"`
}

type A struct {
    A string `json:"a"`
}

type B struct {
    B string `json:"b"`
}

func (f *Foo) UnmarshalJSON(data []byte) error {
    type cloneType Foo

    rawMsg := json.RawMessage{}
    f.Object = &rawMsg

    if err := json.Unmarshal(data, (*cloneType)(f)); err != nil {
        return err
    }

    switch f.Type {
    case "a":
        params := new(A)
        if err := json.Unmarshal(rawMsg, params); err != nil {
            return err
        }
        f.Object = params
    case "b":
        params := new(B)
        if err := json.Unmarshal(rawMsg, params); err != nil {
            return err
        }
        f.Object = params
    default:
        return errors.New("nonsupport type")
    }

    return nil
}

test:

func TestUnmarshal(t *testing.T) {
    foo := &Foo{
        Type:   "a",
        Object: A{A: "rua"},
    }

    bts, err := json.Marshal(foo)
    require.Nil(t, err)
    t.Logf("jsonStr = %s", bts)

    newFoo := new(Foo)
    err = json.Unmarshal(bts, newFoo)
    require.Nil(t, err)
    t.Logf("struct = %+v, object = %+v", newFoo, newFoo.Object)
}

上述代码通过UnmarshalJSON来自定义json unmarshal,先将object赋值为json.RawMessage,再判断type将RawMessage解析到对应结构体,实现delay unmarshal。

这里有一个问题就是在UnmarshalJSON中对相同结构体使用json.Unmarshal会无限递归调用导致StackOverflow,所以新建了一个cloneType。

其实还有一种方法,就是先解析到map,再json.Marshal将map编码为jsonStr,再判断type解析到对应结构体。这种方法多了两个步骤,性能应该不如上面的方法。

https://stackoverflow.com/que...


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK