Як перевірити наявність порожньої структури?


110

Я визначаю структуру ...

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

Іноді я призначаю йому порожній сеанс (тому що нуль неможливий)

session = Session{};

Потім я хочу перевірити, чи він порожній:

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

Очевидно, це не працює. Як це написати?


4
Сесія {} не є "порожнім" сеансом; воно ініціалізується, коли кожне поле є нульовим значенням.
Пол Ханкін

Відповіді:


177

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

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

приклад ігрового майданчика

Через неоднозначність розбору потрібні дужки навколо складеного прямого знака в умові if.

Використання ==вище стосується конструкцій, де всі поля порівнянні . Якщо структура містить непорівнянне поле (фрагмент, карта чи функція), то поля необхідно порівнювати по одному з їх нульовими значеннями.

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

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

4
@kristen Dereference вказівник та порівняння. Якщо sessionце не-нульове значення *Session, тоді використовуйте if (Session{} == *session {.
Булочка Топ

3
Тож я отримую помилку, struct containing []byte cannot be comparedтому що, ну, моя структура містить фрагмент байта.
Ніколи більше

14
@ Ніколи Більше того, відповідь стосується структури із порівнянними полями. Якщо ваша структура містить непорівнянні значення, такі як байт [], вам потрібно написати код для перевірки всіх полів або використовувати пакет відображення, як зазначено в іншій відповіді.
Булочка вгорі

2
Як зазначає @Nevermore, ==порівняння з полями зрізів не вдасться. Для порівняння цих структур, використання або reflect.DeepEqualабо розглянути що - то більш спеціалізоване , як обговорювався тут: stackoverflow.com/questions/24534072 / ...
asgaines

"розбір неоднозначності в [якщо умова]" врятував мені день, спасибі :) coz, коли я пробував це в fmt.Println (session == Session {}), він працює.
Франва

37

Ось ще 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)
}

Чудова відповідь. Дякую, ікза!
Євгеній Голдін

Дивовижна відповідь! Я думаю, що слідування останнього вибору виглядає досить ідіоматично.
DeivinsonTejeda

19

Використання refle.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
використовуючи refle.DeepEqual - це дуже чисте рішення, але мені цікаво, чи потрібно більше часу на обробку? я припускаю, що вона порівнює кожне поле, плюс ви вводите новий імпорт.
туп

4

Майте на увазі, що за допомогою покажчиків на структуру вам доведеться знеструмлювати змінну, а не порівнювати її з вказівником на порожню структуру:

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.