如何检查空结构?

时间:2015-02-11 05:37:18

标签: struct go

我定义了一个结构...

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

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

session = Session{};

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

if session == Session{} {
     // do stuff...
}

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

8 个答案:

答案 0 :(得分:118)

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

if (Session{}) == session  {
    fmt.Println("is zero value")
}

playground example

由于parsing ambiguity,if条件下的复合文字周围需要括号。

以上==的使用适用于所有字段均为comparable的结构。如果结构包含不可比较的字段(切片,映射或函数),则必须逐个将字段与其零值进行比较。

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

if session.playerId == "" {
    fmt.Println("is zero value")
}

答案 1 :(得分:24)

以下是其他3项建议或技巧:

使用附加字段

您可以添加一个附加字段来判断结构是否已填充或为空。我有意将其命名为ready而不是empty,因为bool的零值为false,因此如果您创建一个新的结构Session{},则ready 1}}字段将自动false并且它会告诉你真相:结构尚未准备好(它是空的)。

type Session struct {
    ready bool

    playerId string
    beehive string
    timestamp time.Time
}

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

var s Session

if !s.ready {
    // do stuff (populate s)
}

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

使用现有字段的零值

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

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

var s Session

if s.playerId == "" {
    // do stuff (populate s, give proper value to playerId)
}

在这种情况下,值得将此检查合并到isEmpty()方法中,因为此检查取决于实现:

func (s Session) isEmpty() bool {
    return s.playerId == ""
}

使用它:

if s.isEmpty() {
    // do stuff (populate s, give proper value to playerId)
}

将指针用于结构

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

var s *Session

if s == nil {
    s = new(Session)
    // do stuff (populate s)
}

答案 2 :(得分:13)

使用reflect.deepEqualworks,尤其是在结构中有地图时

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")
  } 
}

答案 3 :(得分:8)

快速补充一下,因为我今天解决了同一问题:

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

if reflect.ValueOf(session).IsZero() {
     // do stuff...
}

我没有针对性能进行测试,但是我想这应该比通过reflect.DeepEqual()进行比较要快。

答案 4 :(得分:1)

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

session := &Session{}
if (Session{}) == *session {
    fmt.Println("session is empty")
}

选中playground

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

答案 5 :(得分:0)

作为其他答案的替代方法,如果您通过case语句而不是if语句执行此语法,则可以使用与您最初预期方式类似的语法执行此操作:

session := Session{}
switch {
case Session{} == session:
    fmt.Println("zero")
default:
    fmt.Println("not zero")
}

playground example

答案 6 :(得分:0)

@cerise-limón 的 answer 是最好的。但是,如果您收到如下所示的 struct containing ... cannot be compared 错误。

type Friends struct {
    nice []string
    mute []string
}

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

func main() {
    session := Session{}
    if (Session{}) == session  {
        fmt.Println("zero")
    }
}

// Output: ./prog.go:23:17: invalid operation: Session{} == session (struct containing Friends cannot be compared)

上面的 Friends' 对象导致了错误。

修复它的简单方法是在字段中定义一个指针。

type Friends struct {
    nice []string
    mute []string
    
}

type Session struct {
    playerId  string
    beehive   string
    timestamp time.Time
    friends   *Friends // <--- here
}

func main() {
    session := Session{}
    if (Session{}) == session  {
        fmt.Println("zero")
    }
}

// Output: zero

答案 7 :(得分:-1)

也许像this

package main

import "fmt"
import "time"

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

func (s Session) Equal(o Session) bool {
   if(s.playerId != o.playerId) { return false }
   if(s.beehive != o.beehive) { return false }
   if(s.timestamp != o.timestamp) { return false }
   return true
}

func (s Session) IsEmpty() bool {
    return s.Equal(Session{})
}

func main() {
    x := Session{}
    if x.IsEmpty() {
       fmt.Print("is empty")
    } 
}