如何检查空结构?

Mic*_*ael 84 struct go

我定义了一个结构...

type Session struct {
    playerId string
    beehive string
    timestamp time.Time
}
Run Code Online (Sandbox Code Playgroud)

有时我给它分配一个空会话(因为nil是不可能的)

session = Session{};
Run Code Online (Sandbox Code Playgroud)

然后我想检查,如果它是空的:

if session == Session{} {
     // do stuff...
}
Run Code Online (Sandbox Code Playgroud)

显然这不起作用.我怎么写呢?

Cer*_*món 151

您可以使用==与零值复合文字进行比较,因为所有字段都是可比较的:

if (Session{}) == session  {
    fmt.Println("is zero value")
}
Run Code Online (Sandbox Code Playgroud)

操场的例子

由于解析模糊,if条件下的复合文字周围需要括号.

上述用途==适用于所有领域具有可比性的结构.如果结构包含不可比较的字段(切片,映射或函数),则必须逐个将字段与其零值进行比较.

比较整个值的替代方法是比较必须在有效会话中设置为非零值的字段.例如,如果播放器ID必须在有效会话中为!="",请使用

if session.playerId == "" {
    fmt.Println("is zero value")
}
Run Code Online (Sandbox Code Playgroud)

  • @Nevermore答案适用于具有可比较字段的结构.如果您的结构包含不可比较的值,如[] byte,那么您需要编写代码来测试所有字段或使用另一个答案中概述的反射包. (11认同)
  • @kristen取消引用指针并进行比较.如果`session`是一个非零的`*Session`,那么使用`if(Session {} ==*session {`. (4认同)
  • 所以我得到一个错误,`包含[]字节的结构不能被比较,因为,我的结构包含一个字节切片. (3认同)
  • 正如@Nevermore 所提到的,`==` 与切片字段的比较将失败。要比较这些结构,请使用“reflect.DeepEqual”或考虑更专业的内容,例如此处讨论的内容:/sf/ask/1717385071/ (2认同)

icz*_*cza 26

这里有3个建议或技巧:

附加字段

您可以添加一个附加字段来判断结构是否已填充或是否为空.我故意命名它,ready而不是empty因为a的零值boolfalse,所以如果你创建一个新的结构,就像Session{}它的ready字段将是自动的false,它会告诉你真相:结构尚未准备好(它是空的).

type Session struct {
    ready bool

    playerId string
    beehive string
    timestamp time.Time
}
Run Code Online (Sandbox Code Playgroud)

初始化结构时,必须设置readytrue.您isEmpty()不再需要您的方法(尽管您可以根据需要创建一个),因为您可以只测试ready字段本身.

var s Session

if !s.ready {
    // do stuff (populate s)
}
Run Code Online (Sandbox Code Playgroud)

bool随着结构变大或者包含不可比较的字段(例如切片map和函数值),这一个附加字段的重要性增加.

使用现有字段的零值

这与之前的建议类似,但它使用现有字段的零值,当结构不为空时,该值被视为无效.这种可用性取决于实现.

例如,如果在您的示例中您playerId不能为空string "",则可以使用它来测试结构是否为空,如下所示:

var s Session

if s.playerId == "" {
    // do stuff (populate s, give proper value to playerId)
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,值得将此检查合并到一个isEmpty()方法中,因为此检查是依赖于实现的:

func (s Session) isEmpty() bool {
    return s.playerId == ""
}
Run Code Online (Sandbox Code Playgroud)

并使用它:

if s.isEmpty() {
    // do stuff (populate s, give proper value to playerId)
}
Run Code Online (Sandbox Code Playgroud)

将指针用于结构

第二个建议是使用指向你的结构的指针:*Session.指针可以有nil值,因此您可以测试它:

var s *Session

if s == nil {
    s = new(Session)
    // do stuff (populate s)
}
Run Code Online (Sandbox Code Playgroud)

  • 很棒的答案!我认为遵循最后一个选择看起来很惯用。 (2认同)

Shi*_*umi 18

只是一个快速的补充,因为我今天解决了同样的问题:

在 Go 1.13 中,可以使用新isZero()方法:

if reflect.ValueOf(session).IsZero() {
     // do stuff...
}
Run Code Online (Sandbox Code Playgroud)

我没有测试这个关于性能,但我想这应该比通过比较更快reflect.DeepEqual()


Kok*_*zzu 14

使用reflect.deepEqual也很有效,特别是当你在struct中有map时

package main

import "fmt"
import "time"
import "reflect"

type Session struct {
    playerId string
    beehive string
    timestamp time.Time
}

func (s Session) IsEmpty() bool {
  return reflect.DeepEqual(s,Session{})
}

func main() {
  x := Session{}
  if x.IsEmpty() {
    fmt.Print("is empty")
  } 
}
Run Code Online (Sandbox Code Playgroud)

  • 使用reflect.DeepEqual 是一个非常干净的解决方案,但我想知道它是否需要更多的处理时间?我认为它正在比较每个领域,并且您引入了一个新的导入。 (3认同)

sha*_*yyx 6

请记住,使用指向 struct 的指针,您必须取消引用变量,而不是将它与指向空结构的指针进行比较:

session := &Session{}
if (Session{}) == *session {
    fmt.Println("session is empty")
}
Run Code Online (Sandbox Code Playgroud)

检查这个操场

同样在这里你可以看到一个结构包含一个指针切片的属性不能以相同的方式进行比较......