Как проверить пустую структуру?


111

Я определяю структуру ...

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

Иногда я назначаю ему пустой сеанс (потому что nil невозможно)

session = Session{};

Затем я хочу проверить, пусто ли оно:

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

Очевидно, это не работает. Как мне это написать?


4
Сеанс {} не является «пустым» сеансом; он инициализируется с нулевым значением каждого поля.
Пол Ханкин,

Ответы:


180

Вы можете использовать == для сравнения с составным литералом с нулевым значением, потому что все поля сопоставимы :

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

пример игровой площадки

Из-за неоднозначности синтаксического анализа составной литерал в условии if должен заключаться в круглые скобки.

Использование ==вышеуказанного применяется к структурам, в которых все поля сопоставимы . Если структура содержит несопоставимое поле (фрагмент, карта или функция), тогда поля необходимо сравнивать одно за другим с их нулевыми значениями.

Альтернативой сравнению всего значения является сравнение поля, которое должно быть установлено на ненулевое значение в допустимом сеансе. Например, если идентификатор игрока должен быть! = "" В допустимом сеансе, используйте

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

4
@kristen Разыменуйте указатель и сравните. Если не sessionравно нулю *Session, используйте if (Session{} == *session {.
Muffin Top

3
Итак, я получаю сообщение об ошибке, struct containing []byte cannot be comparedпотому что моя структура содержит байтовый фрагмент.
Nevermore

14
@Nevermore Ответ относится к структуре с сопоставимыми полями. Если ваша структура содержит несопоставимые значения, такие как [] byte, вам необходимо написать код для проверки всех полей или использовать пакет отражения, как указано в другом ответе.
Muffin Top

2
Как упоминалось @Nevermore, ==сравнение с полями среза не удастся. Для сравнения этих структур используйте любую из них reflect.DeepEqualили рассмотрите что-нибудь более специализированное, например, обсуждаемое здесь: stackoverflow.com/questions/24534072/…
asgaines

"неоднозначность синтаксического анализа в [if condition]" спасла меня, спасибо :) потому что, когда я пробовал это в fmt.Println (session == Session {}), он работал.
Franva

38

Вот еще 3 предложения или техники:

С дополнительным полем

Вы можете добавить дополнительное поле, чтобы узнать, заполнена ли структура или она пуста. Я намеренно назвал его, readyа не emptyпотому, что нулевое значение a boolравно false, поэтому, если вы создадите новую структуру, Session{}ее readyполе будет автоматически, 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)
}

Отличный ответ. Спасибо, icza!
Евгений Гольдин

Отличный ответ! Я думаю, что последующий выбор выглядит довольно идиоматично.
DeivinsonTejeda

19

Использование Reflekt.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
с помощью reflection.DeepEqual - очень чистое решение, но мне интересно, требуется ли больше времени на обработку? Я предполагаю, что он сравнивает каждое поле, плюс вы вводите новый импорт.
чт

5

Имейте в виду, что с указателями на структуру вам придется разыменовать переменную, а не сравнивать ее с указателем на пустую структуру:

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

Проверь эту площадку .

Также здесь вы можете видеть, что структуру, содержащую свойство, которое является фрагментом указателей, нельзя сравнивать таким же образом ...


0

В качестве альтернативы другим ответам это можно сделать с помощью синтаксиса, аналогичного тому, как вы изначально планировали, если вы сделаете это с помощью caseоператора, а не if:

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")
    } 
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.