为了账号安全,请及时绑定邮箱和手机立即绑定

在结构中表示可选 time.Time 的惯用方式

在结构中表示可选 time.Time 的惯用方式

Go
慕慕森 2023-03-29 17:23:40
我已经阅读了两个可选参数?和Golang 将 nil 作为可选参数传递给函数?仍然想知道我的情况是否更具体。我得到的是:type Periodical struct {    Interval *interval.Interval    StartsAt time.Time    EndsAt   time.Time}表示具有开始日期且可能有也可能没有结束日期的周期性事件(周期性事件运行的时间不确定)。eachYear := Periodical{    interval.Years(1),    StartsAt: time.Parse("2 Jan 2006", "1 Jan 1970")}会扔periodical/periodical.go:31:39: cannot use nil as type time.Time in field value据了解,-我没有指定EndsAt time.Time。但是我在那儿真正做什么呢?我是否被迫有一个特殊的标志来忽略EndsAt这样的事情?type Periodical struct {    Interval     *interval.Interval    StartsAt     time.Time    EndsAt       time.Time    isIndefinite bool       // This looks ugly already}然后如果我想要Yearly/Anually我会做类似的事情eachYear := Periodical{    interval.Years(1),    time.Parse("2 Jan 2006", "1 Jan 1970"),    time.Parse("2 Jan 2006", "1 Jan 1970"),    isIndefinite: true}虽然,我可以在业务逻辑中考虑这个标志,但是这个EndsAt设置为相同(或任何其他)日期看起来有点乏味。我还在 package 上定义了一个方法periodical,它允许像这样有一个简写的定期事件:func Monthly(s, e time.Time) Periodical {    return Periodical{StartsAt: s, EndsAt: e, Interval: interval.Months(1)}}我该怎么做才能省略end(第二个参数)?我是被迫为此使用单独的方法还是做一些看起来有点时髦且缺乏可读性的事情:func Monthly(s time.Time, end ...time.Time) Periodical {    if len(end) == 1  {        return Periodical{            StartsAt: s,            EndsAt: end[0],            Interval: interval.Months(1),            isIndefinite: false}    } else if len(end) > 1 {        panic("Multiple end dates are not allowed, don't know what to do with those")    } else {        return Periodical{            StartsAt: s,            EndsAt: time.Now(),            Interval: interval.Months(1),            isIndefinite: true}    }}虽然它可以解决问题,但它看起来很难看,不是吗?我简洁的一行代码现在分散在几行代码中。所以,这就是为什么我想知道,go 实现我想要做的事情的惯用方式是什么?
查看完整描述

1 回答

?
撒科打诨

TA贡献1934条经验 获得超2个赞

time.Time是一个结构。它的零值——尽管是一个有效的时间值——就像从未使用过一样。您可以利用零值时间来指示丢失或未定义的时间值。甚至有一种Time.IsZero()方法可以告诉您某个time.Time值是否为零值。

请注意,零值时间不是某些其他语言中的 1970 年 1 月 1 日,而是 1 年 1 月 1 日,正如您在 Go Playground上看到的那样。这也记录在time.Time

Time 类型的零值为 1 年 1 月 1 日 00:00:00.000000000 UTC。由于这个时间在实践中不太可能出现,IsZero 方法提供了一种简单的方法来检测未明确初始化的时间。

此外,在创建Periodical值时,使用 keyed composite literal,您可以省略不想设置的字段,从而将它们保留为零值:

eachYear := Periodical{
    Interval: interval.Years(1),
    StartsAt: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
}

请注意,您不能time.Parse()在此复合文字中使用,因为它会返回 2 个值(atime.Time和 an error)。time.Date()要么像上面的例子一样使用,要么先创建时间值(处理错误),然后只使用时间值。

判断是否EndsAt指定:

if eachYear.EndsAt.IsZero() {
    fmt.Println("EndsAt is missing")
}

如果您需要将已设置(非零)的时间值归零,您可以使用time.Time{}复合文字:

eachYear.StartsAt = time.Time{}

另请注意,当编组一个time.Time值时,即使它是零值(因为它是一个有效的时间值),即使您使用该选项,它也会被发送omitempty。在这些情况下,您必须使用*time.Time指针或编写自定义编组器。

查看完整回答
反对 回复 2023-03-29
  • 1 回答
  • 0 关注
  • 83 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信