Come verificare la presenza di una struttura vuota?


110

Definisco una struttura ...

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

A volte gli assegno una sessione vuota (perché zero non è possibile)

session = Session{};

Quindi voglio controllare, se è vuoto:

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

Ovviamente questo non funziona. Come lo scrivo?


4
La sessione {} non è una sessione "vuota"; è inizializzato con ogni campo che è il valore zero.
Paul Hankin

Risposte:


177

Puoi usare == per confrontare con un valore letterale composto zero perché tutti i campi sono confrontabili :

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

esempio di parco giochi

A causa di un'ambiguità di analisi , sono necessarie parentesi attorno al letterale composto nella condizione if.

L'uso di quanto ==sopra si applica alle strutture in cui tutti i campi sono confrontabili . Se la struttura contiene un campo non confrontabile (slice, mappa o funzione), i campi devono essere confrontati uno per uno con i loro valori zero.

Un'alternativa al confronto dell'intero valore consiste nel confrontare un campo che deve essere impostato su un valore diverso da zero in una sessione valida. Ad esempio, se l'ID del giocatore deve essere! = "" In una sessione valida, usa

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

4
@ Kristen Elimina il puntatore e confronta. Se sessionè un non nullo *Session, usa if (Session{} == *session {.
Muffin Top

3
Quindi ottengo un errore, struct containing []byte cannot be comparedperché, beh, la mia struttura contiene una fetta di byte.
Nevermore

14
@Nevermore La risposta si applica a una struttura con campi comparabili. Se la struttura contiene valori non confrontabili come [] byte, è necessario scrivere codice per testare tutti i campi o utilizzare il pacchetto di riflessione come descritto in un'altra risposta.
Muffin Top

2
Come menzionato da @Nevermore, il ==confronto con i campi delle sezioni fallirà. Per confrontandoli con le strutture, utilizzare uno reflect.DeepEqualo prendere in considerazione qualcosa di più specializzata come discusso qui: stackoverflow.com/questions/24534072/...
asgaines

"parsing ambiguity in [if condition]" mi ha salvato la giornata, grazie :) perché quando lo stavo provando in fmt.Println (session == Session {}), funziona.
Franva

37

Ecco altri 3 suggerimenti o tecniche:

Con un campo aggiuntivo

Puoi aggiungere un campo aggiuntivo per sapere se la struttura è stata popolata o è vuota. L'ho chiamato intenzionalmente readye non emptyperché il valore zero di a boolè false, quindi se crei una nuova struttura come il Session{}suo readycampo sarà automaticamente falsee ti dirà la verità: che la struttura non è ancora pronta (è vuota).

type Session struct {
    ready bool

    playerId string
    beehive string
    timestamp time.Time
}

Quando si inizializza la struttura, è necessario impostare readysu true. Il tuo isEmpty()metodo non è più necessario (anche se puoi crearne uno se lo desideri) perché puoi semplicemente testare il readycampo stesso.

var s Session

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

Il significato di questo boolcampo aggiuntivo aumenta man mano che la struttura si ingrandisce o se contiene campi non confrontabili (ad es. Slice mape valori di funzione).

Utilizzo del valore zero di un campo esistente

È simile al suggerimento precedente, ma utilizza il valore zero di un campo esistente che è considerato non valido quando la struttura non è vuota. L'usabilità di questo dipende dall'implementazione.

Ad esempio, se nel tuo esempio il tuo playerIdnon può essere vuoto string "", puoi usarlo per verificare se il tuo struct è vuoto in questo modo:

var s Session

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

In questo caso vale la pena incorporare questo controllo in un isEmpty()metodo perché questo controllo dipende dall'implementazione:

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

E usandolo:

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

Usa il puntatore alla tua struttura

Il secondo suggerimento è quello di utilizzare un puntatore al struct: *Session. I puntatori possono avere nilvalori, quindi puoi testarli:

var s *Session

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

Bella risposta. Grazie, icza!
Evgeny Goldin

Risposta fantastica! Penso che seguire l'ultima scelta sia piuttosto idiomatica.
DeivinsonTejeda

19

Utilizzando reflect.deepEqual anche funziona , soprattutto quando si ha la mappa all'interno della struct

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
utilizzando il Reflect.DeepEqual è una soluzione molto pulita ma mi chiedo se richieda più tempo di elaborazione? presumo che stia confrontando ogni campo, inoltre si introduce una nuova importazione.
Thurt

4

Tieni presente che con i puntatori a struct dovresti dereferenziare la variabile e non confrontarla con un puntatore a struct vuoto:

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

Controlla questo parco giochi .

Anche qui puoi vedere che una struttura che contiene una proprietà che è una fetta di puntatori non può essere confrontata allo stesso modo ...


0

In alternativa alle altre risposte, è possibile farlo con una sintassi simile a quella originariamente intesa se lo fai tramite caseun'istruzione piuttosto che un if:

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

esempio di parco giochi


0

Solo una rapida aggiunta, perché oggi ho affrontato lo stesso problema:

Con Go 1.13 è possibile utilizzare il nuovo isZero()metodo:

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

Non l'ho testato per quanto riguarda le prestazioni, ma immagino che dovrebbe essere più veloce rispetto al confronto tramite reflect.DeepEqual().


-1

Forse qualcosa di simile questo

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")
    } 
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.