Jak sprawdzić pustą strukturę?

110

Definiuję strukturę ...

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

Czasami przypisuję mu pustą sesję (ponieważ zero nie jest możliwe)

session = Session{};

Następnie chcę sprawdzić, czy jest pusty:

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

Oczywiście to nie działa. Jak to napisać?

Michael
źródło
4
Sesja {} nie jest „pustą” sesją; jest inicjowany z każdym polem będącym wartością zerową.
Paul Hankin,

Odpowiedzi:

177

Możesz użyć ==, aby porównać z literałem złożonym o wartości zerowej, ponieważ wszystkie pola są porównywalne :

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

przykład placu zabaw

Ze względu na niejednoznaczność analizy nawiasy są wymagane wokół literału złożonego w warunku if.

Użycie ==powyższego dotyczy struktur, w których wszystkie pola są porównywalne . Jeśli struktura zawiera nieporównywalne pole (wycinek, mapę lub funkcję), wówczas pola należy porównać po kolei z ich wartościami zerowymi.

Alternatywą dla porównania całej wartości jest porównanie pola, które musi mieć ustawioną wartość różną od zera w prawidłowej sesji. Na przykład, jeśli identyfikator gracza musi być! = "" W prawidłowej sesji, użyj

if session.playerId == "" {
    fmt.Println("is zero value")
}
Top Muffin
źródło
4
@kristen Usuń wskaźnik i porównaj. Jeśli sessionjest różna od zera *Session, użyj if (Session{} == *session {.
Muffin Top
3
Otrzymuję więc błąd, struct containing []byte cannot be comparedponieważ, cóż, moja struktura zawiera kawałek bajtu.
Nevermore
14
@Nevermore Odpowiedź dotyczy struktury z porównywalnymi polami. Jeśli twoja struktura zawiera nieporównywalne wartości, takie jak [] bajt, musisz napisać kod, aby przetestować wszystkie pola lub użyć pakietu odzwierciedlającego, jak opisano w innej odpowiedzi.
Muffin Top
2
Jak wspomniał @Nevermore, ==porównanie z polami wycinka zakończy się niepowodzeniem. Aby porównać te struktury, użyj albo reflect.DeepEqualrozważ coś bardziej wyspecjalizowanego, jak omówione tutaj: stackoverflow.com/questions/24534072/ ...
asgaines
"parsowanie niejednoznaczności w [jeśli warunek]" uratowało mi dzień, dzięki :) bo jak próbowałem to w fmt.Println (session == Session {}), działa.
Franva,
37

Oto 3 kolejne sugestie lub techniki:

Z dodatkowym polem

Możesz dodać dodatkowe pole, aby stwierdzić, czy struktura została wypełniona, czy jest pusta. Celowo nadałem mu nazwę, readya nie emptydlatego, że zerową wartością a booljest false, więc jeśli utworzysz nową strukturę, taką jak Session{}jej readypole, będzie ona automatycznie falsei powie Ci prawdę: struktura nie jest jeszcze gotowa (jest pusta).

type Session struct {
    ready bool

    playerId string
    beehive string
    timestamp time.Time
}

Podczas inicjalizacji struct, trzeba ustawić readyna true. Twoja isEmpty()metoda nie jest już potrzebna (chociaż możesz ją utworzyć, jeśli chcesz), ponieważ możesz po prostu przetestować readysamo pole.

var s Session

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

Znaczenie tego jednego dodatkowego boolpola rośnie wraz ze wzrostem struktury lub jeśli zawiera pola, które nie są porównywalne (np. Wycinek mapi wartości funkcji).

Korzystanie z wartości zerowej istniejącego pola

Jest to podobne do poprzedniej sugestii, ale używa wartości zerowej istniejącego pola, które jest uważane za nieprawidłowe, gdy struktura nie jest pusta. Użyteczność tego zależy od implementacji.

Na przykład, jeśli w twoim przykładzie twoja playerIdnie może być pusta string "", możesz jej użyć do sprawdzenia, czy twoja struktura jest pusta w następujący sposób:

var s Session

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

W takim przypadku warto włączyć tę kontrolę do isEmpty()metody, ponieważ ta kontrola jest zależna od implementacji:

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

I używając go:

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

Użyj wskaźnika do swojej struktury

Druga propozycja jest użycie wskaźnika do struktury: *Session. Wskaźniki mogą mieć nilwartości, więc możesz to sprawdzić:

var s *Session

if s == nil {
    s = new(Session)
    // do stuff (populate s)
}
icza
źródło
Świetna odpowiedź. Dziękuję icza!
Evgeny Goldin
Świetna odpowiedź! Myślę, że po ostatnim wyborze wygląda dość idiomatycznie.
DeivinsonTejeda
19

Używanie Reflect.deepEqual również działa , zwłaszcza gdy masz mapę wewnątrz struktury

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")
  } 
}
Kokizzu
źródło
2
Korzystanie z reflektorem DeepEqual to bardzo przejrzyste rozwiązanie, ale zastanawiam się, czy przetwarzanie zajmuje więcej czasu? zakładam, że porównuje każde pole, a dodatkowo wprowadzasz nowy import.
thurt
4

Pamiętaj, że w przypadku wskaźników do struktury musiałbyś wyłuskać zmienną i nie porównywać jej ze wskaźnikiem do pustej struktury:

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

Sprawdź ten plac zabaw .

Również tutaj możesz zobaczyć, że struktura posiadająca właściwość będącą kawałkiem wskaźników nie może być porównywana w ten sam sposób ...

shadyyx
źródło
0

Jako alternatywę dla innych odpowiedzi możesz to zrobić za pomocą składni podobnej do pierwotnie zamierzonej, jeśli robisz to za pomocą caseinstrukcji, a nie if:

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

przykład placu zabaw

ML
źródło
0

Tylko szybki dodatek, ponieważ dzisiaj poruszyłem ten sam problem:

W Go 1.13 można skorzystać z nowej isZero()metody:

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

Nie testowałem tego pod kątem wydajności, ale myślę, że powinno to być szybsze niż porównanie przez reflect.DeepEqual().

Shibumi
źródło
-1

Może coś w tym

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")
    } 
}
Kokizzu
źródło