如何在Golang的Google Datastore中忽略结构体中的零值?

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

How to ignore zero value in struct in Google Datastore for Golang?

问题

我正在尝试使用Google Datastore通过Go语言存储数据。由于EndDate是可选字段,并且不想在该字段中存储零值。如果我为时间字段创建一个指针,Google Datastore将发送错误消息 - datastore: unsupported struct field type: *time.Time

如何忽略结构体中的零值字段?

type Event struct {
    StartDate *time.Time `datastore:"start_date,noindex" json:"startDate"`
    EndDate   *time.Time `datastore:"end_date,noindex" json:"endDate"`
}
英文:

I am trying to use Google Datastore to store data by Go. Since the EndDate is optional field, and don't want to store zero value in that field. If I make a pointer for time field, Google Datastore will send an error message - datastore: unsupported struct field type: *time.Time

How can I ignore zero value field in struct?

type Event struct {
    StartDate time.Time `datastore:"start_date,noindex" json:"startDate"`
    EndDate   time.Time `datastore:"end_date,noindex" json:"endDate"`
}

答案1

得分: 2

默认的保存机制不处理可选字段。一个字段要么始终保存,要么从不保存。不存在“只有在其值不等于某个值时才保存”的情况。

“可选保存属性”被视为自定义行为、自定义保存机制,因此必须手动实现。Go语言实现这一点的方式是在结构体上实现PropertyLoadSaver接口。这里我介绍两种不同的实现方法:

手动保存字段

下面是一个示例,演示如何通过手动保存字段(如果EndDate为零值,则排除它):

type Event struct {
    StartDate time.Time `datastore:"start_date,noindex" json:"startDate"`
    EndDate   time.Time `datastore:"end_date,noindex" json:"endDate"`
}

func (e *Event) Save(c chan<- datastore.Property) error {
    defer close(c)
    // 始终保存 StartDate:
    c <- datastore.Property{Name:"start_date", Value:e.StartDate, NoIndex: true}

    // 仅在 EndDate 不是零值时保存:
    if !e.EndDate.IsZero() {
        c <- datastore.Property{Name:"end_date", Value:e.EndDate, NoIndex: true}
    }
    return nil
}

func (e *Event) Load(c chan<- datastore.Property) error {
    // 加载时不需要更改,调用默认实现:
    return datastore.LoadStruct(e, c)
}

使用另一个结构体

这是另一种使用另一个结构体的方法。Load() 实现始终相同,只有 Save() 不同:

func (e *Event) Save(c chan<- datastore.Property) error {
    if !e.EndDate.IsZero() {
        // 如果 EndDate 不是零值,按通常方式保存:
        return datastore.SaveStruct(e, c)
    }

    // 否则,我们需要一个没有 EndDate 字段的结构体:
    s := struct{ StartDate time.Time `datastore:"start_date,noindex"` }{e.StartDate}
    // 现在可以使用默认的保存机制保存它:
    return datastore.SaveStruct(&s, c)
}
英文:

The default saving mechanism does not handle optional fields. A field is either saved all the time, or never. There is no such thing as "only save if it's value does not equal to something".

The "optionally saved property" is considered a custom behavior, a custom saving mechanism, and as such, it has to be implemented manually. Go's way to do this is to implement the PropertyLoadSaver interface on your struct. Here I present 2 different methods to achieve that:

Manually saving fields

Here is an example how to do it by manually saving the fields (and excluding EndDate if it is the zero value):

type Event struct {
    StartDate time.Time `datastore:&quot;start_date,noindex&quot; json:&quot;startDate&quot;`
    EndDate   time.Time `datastore:&quot;end_date,noindex&quot; json:&quot;endDate&quot;`
}

func (e *Event) Save(c chan&lt;- datastore.Property) error {
    defer close(c)
    // Always save StartDate:
    c &lt;- datastore.Property{Name:&quot;start_date&quot;, Value:e.StartDate, NoIndex: true}

    // Only save EndDate if not zero value:
    if !e.EndDate.IsZero() {
        c &lt;- datastore.Property{Name:&quot;end_date&quot;, Value:e.EndDate, NoIndex: true}
    }
    return nil
}

func (e *Event) Load(c chan&lt;- datastore.Property) error {
    // No change required in loading, call default implementation:
    return datastore.LoadStruct(e, c)
}

With another struct

Here's another way using another struct. The Load() implementation is always the same, only Save() differs:

func (e *Event) Save(c chan&lt;- datastore.Property) error {
    if !e.EndDate.IsZero() {
        // If EndDate is not zero, save as usual:
        return datastore.SaveStruct(e, c)
    }

    // Else we need a struct without the EndDate field:
    s := struct{ StartDate time.Time `datastore:&quot;start_date,noindex&quot;` }{e.StartDate}
    // Which now can be saved using the default saving mechanism:
    return datastore.SaveStruct(&amp;s, c)
}

答案2

得分: 1

在字段标签中使用omitempty。

从文档中可以看到:https://golang.org/pkg/encoding/json/

结构体值被编码为JSON对象。除非满足以下条件,否则每个导出的结构体字段都成为对象的成员:

  • 字段的标签是“-”,或者
  • 字段为空,并且其标签指定了“omitempty”选项。

示例:Field int json:"myName,omitempty"

英文:

Use omitempty in the field tags.
From the docs: https://golang.org/pkg/encoding/json/

> Struct values encode as JSON objects. Each exported struct field
> becomes a member of the object unless
>
> - the field's tag is "-", or
> - the field is empty and its tag specifies the "omitempty" option.
>
> Field int json:&quot;myName,omitempty&quot;

huangapple
  • 本文由 发表于 2015年11月11日 22:22:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/33652561.html
匿名

发表评论

匿名网友

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

确定