web-dev-qa-db-ja.com

空の構造体を確認する方法は?

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

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

空のセッションを割り当てることがあります(nilが不可能なため)

session = Session{};

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

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

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

73
Michael

すべてのフィールドが 比較可能 であるため、==を使用してゼロ値の複合リテラルと比較できます。

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

遊び場の例

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

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

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

if session.playerId == "" {
    fmt.Println("is zero value")
}
126
Cerise Limón

さらに3つの提案またはテクニックがあります。

追加フィールドあり

追加のフィールドを追加して、構造体にデータが入力されているか空かを確認できます。 readyのゼロ値はemptyであるため、boolではなくfalseという名前を意図的に付けました。したがって、Session{} its readyフィールドは自動的にfalseになり、真実がわかります。構造体はまだ準備ができていない(空になっている)ということです。

type Session struct {
    ready bool

    playerId string
    beehive string
    timestamp time.Time
}

構造体を初期化するとき、readytrueに設定する必要があります。 readyフィールド自体をテストするだけなので、isEmpty()メソッドはもう必要ありません(必要に応じて作成できます)。

var s Session

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

この1つの追加boolフィールドの重要性は、構造体が大きくなるにつれて、または比較できないフィールド(スライス、mapおよび関数値など)が含まれる場合に増加します。

既存のフィールドのゼロ値を使用する

これは以前の提案と似ていますが、構造体が空でない場合にinvalidと見なされる既存のフィールドのゼロ値を使用します。これの使いやすさは実装に依存します。

たとえば、あなたの例で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)
}
26
icza

reflect.deepEqual また works を使用して、特に構造内にマップがある場合

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

構造体へのポインタを使用すると、変数を逆参照する必要があり、空の構造体へのポインタと比較しないことに注意してください。

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

これを確認してください playground

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

1
shadyyx

他の回答の代替として、caseではなくifステートメントを使用して行う場合、最初に意図した方法と同様の構文でこれを行うことができます。

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

遊び場の例

0
M.L.