Struct tanımlamak ve oluşturmak
Bir struct tipi adlandırılmış alanlardan oluşan bir listedir. Onu type Name struct { ... } ile tanımlar ve değerleri bir bileşik literal ile oluşturursunuz.
Çıktı:
Ana 31
{Name:Ana Email:ana@example.com Age:32 Admin:false}
{Name: Email: Age:0 Admin:false}
main.User{Name:"Bob", Email:"", Age:0, Admin:false}
%+v alan adlarını, %#v ise Go söz dizimini yazdırır. İkisi de hata ayıklarken bir struct'ı incelemenin en hızlı yoludur.
Aynı tipteki alanlar bir satırı paylaşabilir: X, Y float64. Büyük harfle başlayan alan adları dışa açıktır (diğer paketlere ve encoding/json'a görünür); küçük harfliler değildir.
Literal biçimleri
User{Name: "Ana", Age: 31} // named fields: order-free, omitted fields are zero
User{"Ana", "a@x.com", 31, false} // positional: every field, in order
&User{Name: "Ana"} // pointer to a new struct
new(User) // pointer to a zeroed struct
Adlandırılmış alanları tercih edin. Konumsal literal'ler biri bir alan eklediğinde ya da sırasını değiştirdiğinde bozulur ve go vet başka paketlerdeki struct tipleri için onlar hakkında uyarır (örneğin net/url.Error struct literal uses unkeyed fields). Konumsal biçim Point{1, 2} gibi küçük yerel tipler için sorun değildir.
Varsayılan değer yok: sıfır değerler ve kurucular
Go'da ne alan varsayılanları ne de dilde kurucular vardır. Her alan kendi tipinin sıfır değeriyle başlar: 0, "", false, nil. İki kalıp bu boşluğu doldurur.
Sıfır değeri işe yarar hale getirin. sync.Mutex, bytes.Buffer ve strings.Builder başlatma olmadan çalışır. Bir tipi böyle tasarlayabiliyorsanız öyle yapın.
Bir alanın sıfır olmayan bir varsayılana ihtiyacı varsa ya da bir map gibi bir şeyin ayrılması gerekiyorsa bir NewX fonksiyonu yazın:
NewServer bir pointer döndürür, çünkü sunucunun onu değiştiren metotları vardır ve paylaşılacaktır. Küçük değiştirilemez tipler için struct'ı değer olarak döndürmek de yaygındır (time.Date bir time.Time döndürür).
Struct pointer'ları
Go, alan erişimi için struct pointer'larını otomatik olarak dereference eder. p := &User{} ile (*p).Name değil, p.Name yazarsınız.
Çıktı:
{11 12}
{11 12} {0 12}
{11 0}
Struct'lar değerdir. Atama ve fonksiyon argümanları onları kopyalar; bir pointer ise tek bir tanesini paylaşır. Alan alan yapılan kopyalar sığdır: kopyadaki bir slice ya da map alanı hâlâ aynı veriye işaret eder. Hangisinin ne zaman kullanılacağı için pointer'lar sayfasına bakın.
Anonim struct'lar
Bir struct tipi, adı olmadan satır içinde yazılabilir. Bu, tek seferlik gruplamalar, tabloya dayalı testler ve yalnızca bir kez okuduğunuz JSON'u çözmek için kullanışlıdır.
[]struct{ in string; want int } tablosu bir Go testinin standart biçimidir.
Struct'ları karşılaştırmak
Her alan karşılaştırılabilir olduğunda struct'lar == ile karşılaştırılabilir. Eşitlik, tüm alanların eşit olması demektir. Karşılaştırılabilir struct'lar map anahtarı da olabilir.
Slice ya da map alanları olan bir struct için bir Equal metodu yazın ya da testlerde reflect.DeepEqual ile karşılaştırın.
Struct tag'leri
Tag, bir alanın tipinden sonra gelen bir string literal'idir. Dil onu yok sayar; kütüphaneler onu reflection ile okur. En yaygın okuyucu encoding/json'dur:
Bu {"id":7,"name":"Mug"} yazdırır: tag alanları yeniden adlandırır, omitempty sıfır olan Price'ı atar ve dışa kapalı alan encoder'a görünmez. Tag'ler key:"value" geleneğini izler; birden fazla anahtar boşlukla ayrılır: `json:"name" db:"user_name"`. Hatalı biçimlendirilmiş bir tag sorunsuz derlenir ve sessizce yok sayılır; go vet bunu yakalar. Seçenekleri json sayfası anlatıyor.
Boş struct'lar ve alan sırası
struct{}'in alanı yoktur ve sıfır bayt kaplar. Bir set değeri olarak (map[string]struct{}) ve yalnızca olayın önemli olduğu channel'larda sinyal olarak (chan struct{}) kullanılır.
Alan sırası bellek düzenini etkiler: derleyici alanları hizalamalarına göre doldurur. bool, int64, bool'dan oluşan bir struct 64 bit sistemlerde 24 bayt kaplarken int64, bool, bool 16 bayt kaplar. Bu yalnızca çok sayıda saklanan tipler için önemlidir.
Sık yapılan hatalar
- Bir kopyayı değiştirmek.
for _, u := range users { u.Age++ }her seferinde bir kopyayı değiştirir. İndeksi kullanın:users[i].Age++. - Bir map alanını başlatmayı unutmak. Struct'ın sıfır değeri nil bir map tutar; ona yazmak panic'e yol açar. Bir kurucuda ayırın.
- Bir
sync.Mutextutan struct'ı kopyalamak. Kopyanın kendi kilit durumu olur. Bu tür struct'ları pointer ile aktarın;go vetkopyayı raporlar. - Başka paketlerin tipleri için konumsal literal'ler. Bir alan eklendiğinde bozulurlar.
Sıkça Sorulan Sorular
Go'da bir struct nasıl başlatılır?
Bir bileşik literal ile. Alışılmış biçim adlandırılmış alanlardır: u := User{Name: "Ana", Age: 31}; yazmadığınız her alan sıfır değerini alır. User{} tüm sıfır değerleri, &User{...} bir pointer, new(User) ise sıfırlanmış bir struct'a pointer verir.
Go struct alanları için varsayılan değerleri destekler mi?
Hayır. Her alan kendi tipinin sıfır değeriyle başlar. Kalıp bir kurucu fonksiyondur, func NewServer() *Server { return &Server{Port: 8080} }, ya da tipi sync.Mutex ve bytes.Buffer gibi sıfır değeri zaten işe yarar olacak şekilde tasarlamaktır.
Go'da iki struct nasıl karşılaştırılır?
Her alan karşılaştırılabilirse == ile. Karşılık gelen tüm alanları eşit olan iki struct değeri eşittir. Slice, map ya da fonksiyon alanı içeren bir struct == ile karşılaştırılamaz (derleme hatası); alanları kendiniz karşılaştırın ya da testlerde reflect.DeepEqual kullanın.
Go'da struct tag'leri nedir?
Bir alanın tipinden sonra gelen string literal'leridir, örneğin `json:"name,omitempty"`. Derleyici onları yok sayar; encoding/json, veritabanı sürücüleri ve doğrulayıcılar gibi paketler alanların nasıl kodlanacağını, adlandırılacağını ya da kontrol edileceğini belirlemek için onları reflection ile okur.
Go'da bir struct alan adlarıyla nasıl yazdırılır?
{Name:Ana Age:31} yazdıran fmt.Printf("%+v\n", s) kullanın. %v yalnızca değerleri, %#v ise tip adı dahil Go söz dizimini yazdırır: main.User{Name:"Ana", Age:31}.