不懂就问: go 里面如何自定义外部类型的 json 序列化方式? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
x97bgt
V2EX    Go 编程语言

不懂就问: go 里面如何自定义外部类型的 json 列化方式?

  •  1
     
  •   x97bgt 2022-06-17 14:52:32 +08:00 2787 次点击
    这是一个创建于 1215 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我要 json 序列化一个外部类型的变量,把所有 int 类型变量都序列化成"010101"这种表示。

    类似 Java 里的 Gson ,想把自定义的 int 序列化逻辑注册进去。

    这要怎么做到?

    第 1 条附言    2022-06-17 15:38:41 +08:00

    举个例子。下面的类型都是所引用的库里吗的

    type Person struct { name string age int home Home } type Home struct { number int district string } 

    现在有一个变量

    var p Person 

    我怎么用一种比较优雅的方式来序列化p,把它里面所有的int都序列化成"010101"这种表示?

    第 2 条附言    2022-06-17 15:45:35 +08:00
    问题的根源是,`Person`和`Home`都不是我定义的,我不能为它们增加序列化方法。
    25 条回复    2022-06-20 14:51:34 +08:00
    dreasky
        1
    dreasky  
       2022-06-17 15:00:14 +08:00
    14v45mJPBYJW8dT7
        2
    14v45mJPBYJW8dT7  
       2022-06-17 15:04:10 +08:00
    自定义类型,实现 MarshalJSON 方法

    type MyInt int

    func (v MyInt) MarshalJSON() ([]byte, error) {

    return big.NewInt(int64(int(v) + 1)).Bytes(), nil
    }

    func main() {
    m := MyInt(1)
    json.Marshal(m)
    }
    14v45mJPBYJW8dT7
        3
    14v45mJPBYJW8dT7  
       2022-06-17 15:08:26 +08:00
    #2 代码有点问题,但流程是对的

    return big.NewInt(int64(int(v) + 1)).Bytes(), nil
    x97bgt
        4
    x97bgt  
    OP
       2022-06-17 15:10:37 +08:00
    @dreasky
    @rimutuyuan

    外部类型里的变量是 int ,不是自定义类型。

    这样的话,我还需要对这个外部变量再创建一个自定义类型,然后把 int 字段替换成 MyInt 。

    如果这个外部变量里面又嵌套了其他外部类型,那我都要对他们每个都创建一个自定义类型。这样写太反人类了。。。
    14v45mJPBYJW8dT7
        5
    14v45mJPBYJW8dT7  
       2022-06-17 15:14:29 +08:00
    @x97bgt 只修改最外层即可

    如 type Person struct {name string, age int},只需要实现 Person 的 MarshalJSON ,然后拼接
    x97bgt
        6
    x97bgt  
    OP
       2022-06-17 15:19:41 +08:00
    @rimutuyuan

    有点不大明白。这个 Person 是外部类型,我怎么能实现它的 MarshalJSON ?
    14v45mJPBYJW8dT7
        7
    14v45mJPBYJW8dT7  
       2022-06-17 15:32:50 +08:00
    @x97bgt

    func (p *Person) MarshalJSON() ([]byte, error) {}
    x97bgt
        8
    x97bgt  
    OP
       2022-06-17 15:36:24 +08:00
    @rimutuyuan

    还是有点搞不明白。

    这个 Person 是我所引用的库里的类型。可以给这种外部类型实现新的方法?
    14v45mJPBYJW8dT7
        10
    14v45mJPBYJW8dT7  
       2022-06-17 15:50:21 +08:00
    @x97bgt 那就不能了
    icexin
        11
    icexin  
       2022-06-17 17:16:38 +08:00
    Egfly
        12
    Egfly  
       2022-06-17 17:32:22 +08:00
    土办法,引用第三方库的 struct ,你改变不了。那就在你的代码定义一个相同字段的 struct ,然后实现 MarshalJSON()方法

    多了一步遍历转换的过程,看 OP 能不能接受
    join
        13
    join  
       2022-06-17 17:35:21 +08:00
    随便找段 json 复制进去就能生成对应的 struct 类型了,这个工具我写 go 时经常用。
    https://mholt.github.io/json-to-go/
    zoharSoul
        14
    zoharSoul  
       2022-06-17 17:36:09 +08:00   1
    在 golang 里面应该不行, 大道至简, 别琢磨巧妙的方法了.

    大道至简的要义就是, 嗦就嗦, 多点代码也没啥, 省脑子.
    icexin
        15
    icexin  
       2022-06-17 18:24:15 +08:00   2
    Kisesy
        16
    Kisesy  
       2022-06-17 18:44:38 +08:00
    可以用 github.com/json-iterator/go 的扩展功能给 int 类型注册一个自定义编码
    hxtheone
        17
    hxtheone  
       2022-06-17 19:54:03 +08:00 via iPhone
    原生做法感觉只能定义一个一样的 struct 然后自定义字段序列化方式,加一步数据的转换
    wheeler
        18
    wheeler  
       2022-06-17 21:26:37 +08:00 via iPhone
    go 里方法定义得和类型定义在一个包里,这样应该搞不定。
    x97bgt
        19
    x97bgt  
    OP
       2022-06-17 21:28:48 +08:00
    @cloverstd
    @Kisesy

    这个库貌似可以实现,但实在有点抗拒为了这功能又引入一个新东西。。。多谢老歌
    x97bgt
        20
    x97bgt  
    OP
       2022-06-17 21:34:16 +08:00
    @Egfly
    @icexin
    @hxtheone
    @wheeler

    这也是我想到的:先写一些数据作为中间层,把全部的外部类型都继承一遍。。。。

    没想到只能这么写。。。对 go 这语言改观了。。

    多谢大家
    x97bgt
        21
    x97bgt  
    OP
       2022-06-17 21:34:45 +08:00
    @icexin 代码很贴心,投币感谢了!
    joesonw
        22
    joesonw  
       2022-06-18 00:20:43 +08:00 via iPhone
    你想要的是类似 swift 的 extension ,任意地方可以扩展一个类的方法。这样的坏处是 implicitity ,你用了一堆库,某个库把另一个库的 MashalJSON 给改了,你得到的结果就是一头雾水,明明自己没改呀。
    x97bgt
        23
    x97bgt  
    OP
       2022-06-19 11:42:09 +08:00
    @joesonw
    这个看设计,因为 go 里面的序列化器都是全局的,所以改一个地方就会影响好多个地方。

    像 java 的 Gson 就不会,用的时候新建一个 instance 然后注册进逻辑就可以,只有使用它的地方才带这个逻辑。
    lysS
        24
    lysS  
       2022-06-19 15:06:09 +08:00
    你说的自定义 json 序列化方式是加 tag 吗?

    你可以自定义一个自己的完全一样的 struct
    type MyPerson struct {
    name string `我的自定义 tag`
    age int
    home Home
    }

    然后把 p 强制类型转换后再序列化

    json.Marshal(MyPerson(p))
    x97bgt
        25
    x97bgt  
    OP
       2022-06-20 14:51:34 +08:00
    @lysS 不是。我说的是把'{"name": "Alice", "age": 10, "home": {"district": "XX", "number": 1}}',变成'{"name": "Alice", "age": "1010", "home": {"district": "XX", "number": "01"}}'这样,就是把里面所有的 int 数值类型全部换一个序列化方式。

    是需要引入中间变量
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1056 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 18:32 PVG 02:32 LAX 11:32 JFK 14:32
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86