空の構造体をチェックする方法は?


110

構造体を定義します...

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

時々私はそれに空のセッションを割り当てます(nilは不可能だからです)

session = Session{};

次に、空かどうかを確認します。

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

明らかにこれは機能していません。どうやって書くの?


4
セッション{}は「空の」セッションではありません。各フィールドがゼロ値で初期化されます。
Paul Hankin、2015

回答:


177

あなたはすべてのフィールドがあるので、ゼロ値の複合リテラルと比較するために==を使用することができます匹敵します

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

遊び場の例

解析のあいまいさのため、if条件では複合リテラルの前後に括弧が必要です。

上記の使用は==、すべてのフィールドが比較可能な構造体に適用されます。構造体に比較不可能なフィールド(スライス、マップ、または関数)が含まれている場合、フィールドを1つずつゼロ値と比較する必要があります。

値全体を比較する代わりに、有効なセッションでゼロ以外の値に設定する必要があるフィールドを比較することもできます。たとえば、有効なセッションでプレーヤーIDが!= ""である必要がある場合は、

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

4
@kristenポインターを逆参照して比較します。sessionが非nilの場合は*Session、を使用しますif (Session{} == *session {
マフィントップ

3
struct containing []byte cannot be compared構造体にバイトスライスが含まれているため、エラーが発生します。
2016

14
@Nevermore答えは、同等のフィールドを持つ構造体に適用されます。構造体に[] byteなどの比較できない値が含まれている場合は、すべてのフィールドをテストするコードを記述するか、別の回答で概説されているとおりにReflectパッケージを使用する必要があります。
マフィントップ

2
@Nevermoreが述べたように、==スライスフィールドとの比較は失敗します。これらの構造体を比較するために、使用のいずれかreflect.DeepEqual:以上ここで説明のような特殊な何かを検討stackoverflow.com/questions/24534072/...
asgaines

「[if条件]でのあいまいさの解析」は私の日を救いました、感謝:) coz私がfmt.Println(session == Session {})でそれを試みていたとき、それは機能します。
フランバ

37

さらに3つの提案または手法があります。

追加フィールドあり

追加のフィールドを追加して、構造体が入力されているか空であるかを確認できます。私は意図的にそれに名前を付けましたが、それはaのゼロ値がであるためではreadyありません。したがって、そのフィールドのような新しい構造体を作成すると、フィールドは自動的に作成され、真実がわかります:構造体はまだ準備ができていない(空です)。emptyboolfalseSession{}readyfalse

type Session struct {
    ready bool

    playerId string
    beehive string
    timestamp time.Time
}

構造体を初期化するときは、に設定readyする必要がありますtrue。あなたのisEmpty()あなただけのテストすることができますので、この方法は、(あなたがしたい場合は、1を作成することができますが)もう必要ありませんreadyフィールド自体を。

var s Session

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

この1つの追加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)
}

構造体へのポインターを使用する

2番目の提案は、構造体へのポインタを使用することです*Session。ポインタはnil値を持つことができるので、それをテストできます。

var s *Session

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

すばらしい答えです。ありがとう、icza!
Evgeny Goldin

素晴らしい答えです!最後の選択に従うことはかなり慣用的に見えます。
DeivinsonTejeda 2017年

19

特にstruct内にマップがある場合、reflect.deepEqualの使用も機能します

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

2
Reflect.DeepEqualの使用は非常にクリーンなソリューションですが、処理時間が長くなるのではないでしょうか?私はそれがすべてのフィールドを比較していると仮定し、さらに新しいインポートを導入します。
17

4

構造体へのポインタでは、変数を逆参照する必要があり、空の構造体へのポインタと比較しないでください。

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

この遊び場を確認してください。

また、ここでは、ポインターのスライスであるプロパティを保持する構造体を同じ方法で比較できないことがわかります...


0

他の回答の代わりにcaseif:ではなくステートメントを使用して行う場合は、本来意図したのと同様の構文でこれを行うことができます。

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

遊び場の例


0

今日は同じ問題に取り組んだので、すぐに追加します。

Go 1.13では、新しいisZero()メソッドを使用できます。

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

私はパフォーマンスに関してこれをテストしませんでしたが、これはを介して比較するよりも速いはずですreflect.DeepEqual()


-1

たぶんこのようなもの

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")
    } 
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.