如何使用非空索引和从0开始的列表?

huangapple go评论82阅读模式
英文:

How to use non-nullable indices and 0-indexed lists

问题

如果我在结构体中传递一个int值(在我的特定情况下是rpc参数),语言不允许属性为nil。int的空值是0。

但是Go使用以0为起始的数组索引。我需要一种区分空值和索引为0的方法。是否有一个Go的惯用解决方案来解决这个问题?

// 这是我在遇到这个问题之前写的伪代码
if (args.maybeIndex != nil) {
  doSomething(sliceOfNodes[args.maybeIndex])
}
英文:

If I'm passing an int value in a struct (in my particular case, rpc arguments), the language does not allow the attribute to be nil. The empty value for an int is 0.

But Go uses 0-indexed arrays. I need a way to differentiate between an empty value and an index of 0. Is there an idiomatic go solution for this problem?

// this is psuedo-code I had written before hitting this problem
if (args.maybeIndex != nil) {
  doSomething(sliceOfNodes[args.maybeIndex])
}

答案1

得分: 4

如果您通过值对整数进行编码,那么您对此无能为力 - 默认值为0。

在Go中确保编码中的可空性的常见方法是使用指针类型。使用*int而不是int可以让您区分“无”和0。

例如,考虑以下JSON示例的结构:

type Options struct {
  Id      *string `json:"id,omitempty"`
  Verbose *bool   `json:"verbose,omitempty"`
  Level   *int    `json:"level,omitempty"`
  Power   *int    `json:"power,omitempty"`
}

以及以下数据:

{
  "id": "foobar",
  "verbose": false,
  "level": 10
}

请注意,“power”未指定。您可以编写一个反序列化函数:

func parseOptions(jsn []byte) Options {
  var opts Options
  if err := json.Unmarshal(jsonText, &opts); err != nil {
    log.Fatal(err)
  }

  if opts.Power == nil {
    var v int = 10
    opts.Power = &v
  }

  return opts
}

如果未指定“power”,则将其设置为默认值。这样可以区分“power不存在”和“power存在且其值为0”。


如果您的编码/远程过程调用机制不允许使用指针,您可以通过添加另一个名为“索引存在”的布尔字段来解决此问题。

最后,考虑设计您的程序,使其能够适应“未设置”和“设置为默认值”之间的差异。换句话说,接受默认值和未指定数据是相同的。从长远来看,这将导致更清晰的设计和代码,并且更不容易出错。

英文:

If you encode your ints by value, then there's not much you can do about it - the default value is 0.

A common way to ensure nullability in encodings in Go is to use pointer types. Using a *int instead of an int lets you distinguish between "none" and 0.

E.g. with a JSON example, consider the struct:

type Options struct {
  Id      *string `json:"id,omitempty"`
  Verbose *bool   `json:"verbose,omitempty"`
  Level   *int    `json:"level,omitempty"`
  Power   *int    `json:"power,omitempty"`
}

And this data:

{
  "id": "foobar",
  "verbose": false,
  "level": 10
}

Note that "power" is not specified. You could write a deserializer:

func parseOptions(jsn []byte) Options {
  var opts Options
  if err := json.Unmarshal(jsonText, &opts); err != nil {
    log.Fatal(err)
  }

  if opts.Power == nil {
    var v int = 10
    opts.Power = &v
  }

  return opts
}

That sets a default value to "power", if it's not specified. This lets you distinguish between "power was not present" and "power was present and its value was 0".


If your encoding / RPC mechanism does not permit pointers, you could work around this by having another boolean field called "index present" or something like this.

Finally, consider designing your program to make it resilient to the difference between "not set" and "set to default value". IOW, just accept that default values and unspecified data are one and the same. In the long term, this will result in a cleaner design and code, and will be less error prone.

huangapple
  • 本文由 发表于 2021年7月10日 23:49:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/68329289.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定