Ce face struct și struct-uri
Un struct adună mai multe valori, numite câmpuri, într-o singură valoare: un elev are nume, notă și email. De obicei i se dă un nume cu type Elev struct { ... }. Câmpurile se accesează cu punct: e.Nume. Câmpurile cu literă mare sunt vizibile din alte pachete, cele cu literă mică nu.
Un struct se creează cu un literal: cu numele câmpurilor (Elev{Nume: "Ana"}, recomandat; câmpurile lipsă primesc valoarea zero) sau pozițional (Elev{"Ana", 9.5, ""}, fragil când se adaugă câmpuri). Struct-urile sunt valori: atribuirea copiază toate câmpurile, iar două struct-uri cu câmpuri comparabile se pot compara cu ==.
Textul dintre apostroafe inverse de după un câmp (`json:"email"`) este un tag: informație citită de pachete precum encoding/json. Struct-urile primesc comportament prin metode și pot include alte struct-uri (embedding). struct{} (fără câmpuri) nu ocupă memorie și se folosește ca semnal în canale sau ca valoare în map-uri folosite ca mulțimi.
Exemple
Exemplul 1: Definire, creare și modificare
%+v afișează și numele câmpurilor.
package main
import "fmt"
type Elev struct {
Nume string
Clasa string
Nota float64
}
func main() {
a := Elev{Nume: "Ana", Clasa: "a X-a B", Nota: 9.5}
m := Elev{Nume: "Mihai"} // Clasa = "", Nota = 0
m.Nota = 7.25
fmt.Printf("%+v\n", a)
fmt.Printf("%+v\n", m)
fmt.Println(a.Nume, "are", a.Nota)
copie := a
copie.Nota = 4
fmt.Println("originalul are tot", a.Nota)
}
Rezultat
{Nume:Ana Clasa:a X-a B Nota:9.5}
{Nume:Mihai Clasa: Nota:7.25}
Ana are 9.5
originalul are tot 9.5
Exemplul 2: Slice de struct-uri și struct anonim
package main
import "fmt"
type Produs struct {
Nume string
Pret float64
Bucati int
}
func main() {
cos := []Produs{
{"pâine", 4.5, 2},
{"lapte", 7.99, 1},
{"cașcaval", 32.0, 1},
}
total := 0.0
for _, p := range cos {
total += p.Pret * float64(p.Bucati)
}
fmt.Printf("total: %.2f lei\n", total)
punct := struct{ X, Y int }{3, 4} // struct fără nume, folosit o dată
fmt.Println(punct.X, punct.Y)
}
Rezultat
total: 48.99 lei
3 4
Exemplul 3: Tag-uri pentru JSON
omitempty omite câmpul gol; - nu îl scrie niciodată.
package main
import (
"encoding/json"
"fmt"
)
type Utilizator struct {
Nume string `json:"nume"`
Email string `json:"email,omitempty"`
Parola string `json:"-"`
Varsta int `json:"varsta"`
}
func main() {
u := Utilizator{Nume: "Ioana", Parola: "secret", Varsta: 24}
date, _ := json.Marshal(u)
fmt.Println(string(date))
}
Rezultat
{"nume":"Ioana","varsta":24}
Greșeli frecvente
- Literal pozițional cu mai puține valori decât câmpuri:
too few values in struct literal of type Elev. Folosește numele câmpurilor. - Modificarea unei copii (de exemplu variabila din
for _, p := range cos) crezând că schimbi elementul: scriecos[i].Pret = .... - Tag JSON cu spații sau ghilimele greșite (
`json: "nume"`):go vetavertizeazăstruct field tag ... not compatible with reflect.StructTag.Get.
Comenzi înrudite
metode: Funcții legate de un tip prin receptor; cu receptor pointer pot modifica valoarea pe care sunt apelate.embedding (încorporare): Include un tip în altul fără nume de câmp; câmpurile și metodele lui devin accesibile direct (compoziție).pointeri (* și &): Un pointer (*T) ține adresa unei variabile; prin el funcțiile pot modifica valoarea originală.vizibilitate (exportat/neexportat): Numele care încep cu literă mare sunt vizibile din alte pachete; cele cu literă mică rămân private pachetului.type: Definește un tip nou (pe baza altuia, struct, interfață, funcție) sau un alias pentru un tip existent.