Boş bir yapı nasıl kontrol edilir?


110

Bir yapı tanımlıyorum ...

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

Bazen boş bir oturum atarım (çünkü nil mümkün değildir)

session = Session{};

Sonra boş olup olmadığını kontrol etmek istiyorum:

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

Açıkçası bu işe yaramıyor. Nasıl yazacağım?


4
{} Oturumu "boş" bir oturum değil; her alan sıfır değer olacak şekilde başlatılır.
Paul Hankin

Yanıtlar:


178

Tüm alanlar karşılaştırılabilir olduğundan, sıfır değerli birleşik değişmez değerle karşılaştırmak için == kullanabilirsiniz :

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

oyun alanı örneği

Ayrıştırma belirsizliği nedeniyle , if koşulundaki bileşik değişmez değeri etrafında parantezler gereklidir.

Yukarıdakilerin kullanımı, ==tüm alanların karşılaştırılabilir olduğu yapılar için geçerlidir . Yapı karşılaştırılamaz bir alan (dilim, harita veya işlev) içeriyorsa, alanlar birer birer sıfır değerleriyle karşılaştırılmalıdır.

Tüm değeri karşılaştırmanın bir alternatifi, geçerli bir oturumda sıfır olmayan bir değere ayarlanması gereken bir alanı karşılaştırmaktır. Örneğin, geçerli bir oturumda oyuncu kimliği! = "" Olması gerekiyorsa, şunu kullanın:

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

4
@kristen İşaretçiyi kaldırın ve karşılaştırın. sessionSıfır değilse *Session, o zaman kullanın if (Session{} == *session {.
Muffin Top

3
Bu yüzden bir hata alıyorum, struct containing []byte cannot be comparedçünkü yapımda bir bayt dilimi var.
Nevermore

14
@Nevermore Cevap, karşılaştırılabilir alanlara sahip bir yapı için geçerlidir. Yapınız [] bayt gibi karşılaştırılamaz değerler içeriyorsa, tüm alanları test etmek için kod yazmanız veya başka bir yanıtta belirtildiği gibi yansıtma paketini kullanmanız gerekir.
Muffin Top

2
@Nevermore'da belirtildiği gibi, ==dilim alanlarıyla karşılaştırma başarısız olacaktır. Bu yapıları karşılaştırmak için, bunlardan birini kullanın reflect.DeepEqualveya burada tartışıldığı gibi daha özel bir şey düşünün: stackoverflow.com/questions/24534072/…
asgaines

"[eğer koşulda] ayrıştırma belirsizliği" günümü kurtardı, teşekkürler :) coz fmt.Println'de (session == Session {}) denediğimde işe yarıyor.
Franva

37

İşte 3 öneri veya teknik daha:

Ek Alanla

Yapının doldurulup doldurulmadığını veya boş olup olmadığını anlamak için ek bir alan ekleyebilirsiniz. Ben kasıtlı olarak adlandırılmış readyolup empty, bir sıfır değeri nedeniyle boololduğu false, oluşturmak eğer öyleyse gibi yeni bir yapı Session{}kendi readyalanında otomatik olacak falseve size doğruyu söyleyecektir: struct zaman henüz (o boş) hazır olduğunu söyledi.

type Session struct {
    ready bool

    playerId string
    beehive string
    timestamp time.Time
}

Yapıyı başlattığınızda, ayarlamanız readygerekir true. Sizin isEmpty()sadece test edebilirsiniz çünkü (isterseniz bir tane oluşturabilirsiniz rağmen) yöntemi artık gerekli değildir readyalanını kendisi.

var s Session

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

boolYapı büyüdükçe veya karşılaştırılabilir olmayan alanlar (örneğin, dilim mapve fonksiyon değerleri) içerdiğinde , bu ek alanın önemi artar .

Mevcut Bir Alanın Sıfır Değerini Kullanma

Bu önceki öneriye benzer, ancak yapı boş olmadığında geçersiz kabul edilen mevcut bir alanın sıfır değerini kullanır . Bunun kullanılabilirliği uygulamaya bağlıdır.

Örneğin, örneğinizde playerIdboş string ""olamazsanız, yapınızın şu şekilde boş olup olmadığını test etmek için kullanabilirsiniz:

var s Session

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

Bu durumda, bu denetimi bir isEmpty()yönteme dahil etmeye değer çünkü bu denetim uygulamaya bağlıdır:

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

Ve bunu kullanarak:

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

Yapınız için İşaretçiyi kullanın

İkinci öneri, yapı için bir işaretçi kullanmaktır: *Session. İşaretçilerin nildeğerleri olabilir , böylece test edebilirsiniz:

var s *Session

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

Mükemmel cevap. Teşekkür ederim icza!
Evgeny Goldin

Harika cevap! Bence son seçimi takip etmek oldukça deyimsel görünüyor.
DeivinsonTejeda

19

Reflekt.deepEqual kullanmak , özellikle yapının içinde haritanız olduğunda da işe yarar

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 kullanımı çok temiz bir çözüm ancak daha fazla işlem süresi mi gerektiriyor? Her alanı karşılaştırdığını varsayıyorum, ayrıca yeni bir içe aktarım getiriyorsunuz.
thurt

5

Yapılandırılacak işaretçilerle değişkenin referansını kaldırmanız ve onu boş yapıya bir gösterici ile karşılaştırmanız gerekmediğini unutmayın:

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

Bu oyun alanını kontrol edin .

Ayrıca burada, bir işaretçi dilimi olan bir özelliği tutan bir yapının aynı şekilde karşılaştırılamayacağını görebilirsiniz ...


0

Diğer yanıtlara alternatif olarak, bunu bir caseifade yerine bir ifade yoluyla yaparsanız, bunu başlangıçta amaçladığınız şekle benzer bir sözdizimi ile yapmak mümkündür if:

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

oyun alanı örneği


0

Hızlı bir ekleme, çünkü bugün aynı sorunu ele aldım:

Go 1.13 ile yeni isZero()yöntemi kullanmak mümkündür :

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

Bunu performansla ilgili olarak test etmedim, ancak sanırım bu, karşılaştırmaktan daha hızlı olmalı reflect.DeepEqual().


-1

Belki bunun gibi bir şey

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")
    } 
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.