Bagaimana cara memeriksa struct kosong?

110

Saya mendefinisikan struktur ...

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

Terkadang saya menetapkan sesi kosong untuk itu (karena nihil tidak mungkin)

session = Session{};

Lalu saya ingin memeriksa, apakah kosong:

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

Jelas ini tidak berhasil. Bagaimana cara menulisnya?

Michael
sumber
4
Sesi {} bukanlah sesi "kosong"; itu diinisialisasi dengan setiap bidang menjadi nilai nol.
Paul Hankin

Jawaban:

177

Anda dapat menggunakan == untuk membandingkan dengan literal komposit nilai nol karena semua bidang dapat dibandingkan :

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

contoh taman bermain

Karena ambiguitas penguraian , tanda kurung diperlukan di sekitar literal komposit dalam kondisi if.

Penggunaan di ==atas berlaku untuk struct yang semua bidangnya sebanding . Jika struct berisi bidang yang tidak dapat dibandingkan (irisan, peta, atau fungsi), bidang tersebut harus dibandingkan satu per satu dengan nilai nolnya.

Alternatif untuk membandingkan seluruh nilai adalah dengan membandingkan bidang yang harus disetel ke nilai bukan nol dalam sesi yang valid. Misalnya, jika id pemain harus! = "" Dalam sesi yang valid, gunakan

if session.playerId == "" {
    fmt.Println("is zero value")
}
Muffin Top
sumber
4
@ Kristen Merujuk penunjuk dan membandingkan. Jika sessionbukan nol *Session, maka gunakan if (Session{} == *session {.
Muffin Top
3
Jadi saya mendapatkan kesalahan, struct containing []byte cannot be comparedkarena, well, struct saya berisi potongan byte.
Nevermore
14
@Nevermore Jawabannya berlaku untuk struct dengan bidang yang sebanding. Jika struct Anda berisi nilai yang tidak dapat dibandingkan seperti [] byte, maka Anda perlu menulis kode untuk menguji semua bidang atau menggunakan paket refleksi seperti yang dijelaskan dalam jawaban lain.
Muffin Top
2
Seperti yang disebutkan oleh @Nevermore, ==perbandingan dengan bidang potongan akan gagal. Untuk membandingkan struct ini, gunakan salah satu reflect.DeepEqualatau pertimbangkan sesuatu yang lebih khusus seperti yang dibahas di sini: stackoverflow.com/questions/24534072/…
asgaines
"parsing ambiguity in [if condition]" menyelamatkan hari saya, terima kasih :) karena saat saya mencobanya di fmt.Println (session == Session {}), berhasil.
Franva
37

Berikut adalah 3 saran atau teknik lainnya:

Dengan Bidang Tambahan

Anda dapat menambahkan bidang tambahan untuk mengetahui apakah struct telah diisi atau kosong. Aku sengaja menamakannya readydan tidak emptykarena nilai nol dari booladalah false, jadi jika Anda membuat struct baru seperti Session{}yang readylapangan akan secara otomatis falsedan akan memberitahu Anda kebenaran: bahwa struct tidak-belum siap (itu kosong).

type Session struct {
    ready bool

    playerId string
    beehive string
    timestamp time.Time
}

Saat Anda menginisialisasi struct, Anda harus mengatur readyke true. isEmpty()Metode Anda tidak diperlukan lagi (meskipun Anda dapat membuatnya jika Anda mau) karena Anda dapat menguji readybidang itu sendiri.

var s Session

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

Signifikansi dari satu boolbidang tambahan ini meningkat saat struct tumbuh lebih besar atau jika berisi bidang yang tidak sebanding (misalnya irisan, mapdan nilai fungsi).

Menggunakan Nilai Nol dari Bidang yang Ada

Ini mirip dengan saran sebelumnya, tetapi menggunakan nilai nol dari bidang yang ada yang dianggap tidak valid jika struct tidak kosong. Kegunaan ini bergantung pada implementasi.

Misalnya jika dalam contoh Anda playerIdtidak boleh kosong string "", Anda dapat menggunakannya untuk menguji apakah struct Anda kosong seperti ini:

var s Session

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

Dalam hal ini, ada baiknya menggabungkan pemeriksaan ini ke dalam isEmpty()metode karena pemeriksaan ini bergantung pada implementasi:

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

Dan menggunakannya:

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

Gunakan Pointer ke struct Anda

Saran kedua adalah dengan menggunakan Pointer untuk struct Anda: *Session. Pointer dapat memiliki nilnilai, jadi Anda dapat mengujinya:

var s *Session

if s == nil {
    s = new(Session)
    // do stuff (populate s)
}
icza
sumber
Jawaban yang bagus. Terima kasih, icza!
Evgeny Goldin
Jawaban yang luar biasa! Saya pikir mengikuti pilihan terakhir terlihat sangat idiomatis.
DeivinsonTejeda
19

Menggunakan reflect.deepEqual juga berfungsi , terutama ketika Anda memiliki peta di dalam 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")
  } 
}
Kokizzu
sumber
2
menggunakan reflect.DeepEqual adalah solusi yang sangat bersih tetapi saya bertanya-tanya apakah itu membutuhkan lebih banyak waktu pemrosesan? saya berasumsi itu membandingkan setiap bidang, ditambah Anda memperkenalkan impor baru.
Menyemburkan
4

Ingatlah bahwa dengan pointer ke struct Anda harus mendereferensi variabel dan tidak membandingkannya dengan pointer ke struct kosong:

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

Periksa taman bermain ini .

Juga di sini Anda dapat melihat bahwa struct yang memiliki properti yang merupakan potongan pointer tidak dapat dibandingkan dengan cara yang sama ...

shadyyx
sumber
0

Sebagai alternatif dari jawaban lain, dimungkinkan untuk melakukan ini dengan sintaks yang mirip dengan cara yang Anda maksudkan jika Anda melakukannya melalui casepernyataan daripada if:

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

contoh taman bermain

ML
sumber
0

Hanya tambahan cepat, karena saya menangani masalah yang sama hari ini:

Dengan Go 1.13, dimungkinkan untuk menggunakan isZero()metode baru :

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

Saya tidak menguji ini terkait kinerja, tetapi saya rasa ini seharusnya lebih cepat, daripada membandingkan melalui reflect.DeepEqual().

Shibumi
sumber
-1

Mungkin seperti ini

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
sumber