如何区分 int null 和默认为零与 int 实际上等于零?

How to differentiate int null and defaulted to zero from int actually equal to zero?

我很长一段时间 python 用户转向 Go,我仍然有一些问题需要重新获得管理打字和指针的基本技能。

我有一个程序从 RabbitMq 接收事件(但无论我们谈论的是什么传输,问题都是一样的)。其中之一甚至包含一个类型为 int 的可选字段 F1。

我的理解是,如果该字段不存在于事件中,那么 go 会将其默认为 0。但是 0 是该字段的有效值,我需要区分值为 0 的情况,以及值未定义的情况。

我想将我的字段设为 *int 以实际将“nil”作为值。但是当一个接收到一个事件时,F1 会被设置为实际指向的值,还是来自发送者的值地址? 我还有其他选择吗?

在大多数情况下,使用指向值的指针是有意义的。例如

type RabbitMessage struct {
    F1 *int `json:"f1"`
}

这将如何工作的确切细节取决于您在通过 RabbitMQ 发送数据之前如何序列化数据。如果您使用 JSON,那么这应该没有问题,因为空值和省略值在 Go 中都将表示为 nil。当提供该值时,它将被设置为您期望的值(它不会使用发件人的地址)。

如果您只控制接收器程序,那么 AFAICT 您无法区分已自动初始化为 0 的 int 和已被设置为 0 的 int发件人。

如果您可以修改发件人程序,则另一种方法是在您的 int 中添加一个布尔字段,以告知是否设置了 int。然后在接收端你可以检查布尔值是否为真。

您还可以发送一个指向 int 的指针:

type Message struct {
    Value *int `json:"value"`
}

message := Message{Value: 4}

请注意,在解组时您会得到一个 int 指针,您需要取消引用。

"Do I have any other alternative?" -- 是的,可以自定义类型,类似于sql.NullInt64.

type OptionalInt struct {
    Int     int
    IsValid bool
}

func NewOptionalInt(i int) OptionalInt {
    return OptionalInt{Int: i, IsValid: true}
}

func (o *OptionalInt) UnmarshalJSON(data []byte) error {
    if string(data) != "null" {
        if err := json.Unmarshal(data, &o.Int); err != nil {
            return err
        }
        o.IsValid = true
    }
    return nil
}

func (o OptionalInt) MarshalJSON() ([]byte, error) {
    if o.IsValid {
        return json.Marshal(o.Int)
    }
    return json.Marshal(nil)
}