我读过Optional Parameters?和Golang pass nil as optional argument to a function?
并且仍然想知道我的案例是否更具体。
我得到的是:
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
看起来有点沉闷。
我还在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}
}
}
虽然它有诀窍,看起来很难看,不是吗?我简洁的单行代码现在分散在几行代码中。
所以,这就是为什么我想知道,实现我想做的事情的惯用方法是什么?
time.Time
是一个结构。它的zero value - 虽然是一个有效的时间价值 - 就像从未使用过。您可以利用零值时间来指示缺失或未定义的时间值。甚至有一个Time.IsZero()
方法告诉你time.Time
值是否为零值。
请注意,零值时间不是像其他语言一样,1970年1月1日,但是1月1日,正如您在Go Playground上看到的那样。这也记录在time.Time
:
Time类型的零值是1月1日,第1年00:00:00.000000000 UTC。由于这个时间不太可能在实践中出现,因此IsZero方法提供了一种检测尚未明确初始化的时间的简单方法。
此外,在创建Periodical
值时,使用键控composite literal,您可以省略您不想设置的字段,从而将它们保留为零值:
eachYear := Periodical{
Interval: interval.Years(1),
StartsAt: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC),
}
请注意,您不能在此复合文字中使用time.Parse()
,因为它返回2个值(time.Time
和error
)。如上例所示使用time.Date()
,或者先创建时间值(句柄错误),然后使用时间值。
要判断是否指定了EndsAt
:
if eachYear.EndsAt.IsZero() {
fmt.Println("EndsAt is missing")
}
如果您需要将已设置(非零)时间值归零,则可以使用time.Time{}
复合文字:
eachYear.StartsAt = time.Time{}
另请注意,当编组time.Time
值时,即使它是零值(因为它是有效时间值),即使您使用omitempty
选项,也会发送它。在这些情况下,您必须使用*time.Time
指针或编写自定义封送程序。有关详细信息,请参阅Golang JSON omitempty With time.Time Field。