将缺失的字段解组为空映射

问题描述 投票:0回答:1
type FieldDefinition struct {
    Name        string   `json:"name"`
    Description string   `json:"description"`

    Aspects map[string]string `json:"aspects"`
}

func (f *FieldDefinition) UnmarshalJSON(b []byte) error {
    var tmp struct {
        Name        string   `json:"name"`
        Description string   `json:"description"`

        Aspects map[string]string `json:"aspects"`
    }

    err := json.Unmarshal(b, &tmp)
    if err != nil {
        return err
    }

    if tmp.Aspects == nil {
        tmp.Aspects = make(Aspects)
    }

    *f = tmp

    return nil
}

如果我在没有

{"description": "desc","name": "name"}
字段的情况下解组
aspects
,则
Aspects
将为零。

添加

UnmarshalJSON
功能即可解决

但是有两个问题。 一个是如果一个strcut嵌入

FieldDefinition
例如

type PropertyDefinition struct {
    FieldDefinition
    SourceName string     `json:"sourceName"`
}

json.Unmarshal
会打电话给
FieldDefinition.UnmarshalJSON
并让
SourceName
保持不变。

我也可以加

PropertyDefinition.UnmarshalJson
,但是很有感染力

另一个是

tmp
结构体在重复
FieldDefinition
,这是轻微的,我可以忍受。

https://github.com/golang/go/issues/27589相关

json go unmarshalling
1个回答
0
投票

tmp 结构重复 FieldDefinition,这是次要的,我可以忍受。

你不需要这样做。您可以在

FieldDefinition
上创建另一个类型,新类型将没有
UnmarshalJSON
方法,例如:

func (f *FieldDefinition) UnmarshalJSON(b []byte) error {
    type newType FieldDefinition

    var target newType
    target.Aspects = make(map[string]string) // ensures map always non-nil
    err := json.Unmarshal(b, &target)
    if err != nil {
        return err
    }

    *f = (FieldDefinition)(target)

    return nil
}

对于您关于

FieldDefinition.UnmarshalJSON
暴露给嵌入它的结构的其他问题,不幸的是,如果使用来自 std lib 的
encoding/json
要求,则没有一个好的方法来解决这个问题。如果将它作为一个命名字段而不是嵌入一个选项,那么这将不再是一个问题。

但我认为您不需要自定义

UnmarshalJSON
来确保地图始终是非零的。

如果

Aspects
地图预计对它的消费者是只读的,那么 go 对 nil 地图的处理应该已经很好地适用于这个用例,因为从 nil 地图读取一个键不会恐慌 - 它只会表现得好像钥匙不在那里:

package main

import "fmt"

func main() {
    var m map[string]string = nil
    value, exists := m["foo"]
    fmt.Println("value", value)
    fmt.Println("exists", exists)
    // prints
    // value 
    // exists false
}

此外,如果消费者需要消除是否设置了

Aspects
映射的歧义,他们现在可以检查该结构字段是否为
nil

所以这是假设

Aspects
地图只是只读的。

如果消费者也将在 JSON 解码后更新

Aspects
地图,那么您可以 1)期望消费者负责检查 nil 并在需要时实例化地图,或者 2)提供辅助方法,例如
FieldDefinition.SetAspectField(string, string)
可以处理为消费者实例化地图。

© www.soinside.com 2019 - 2024. All rights reserved.