Exercice - Utiliser des structs
Il peut arriver que vous deviez représenter une collection de champs dans une structure. Par exemple, lorsque vous devez écrire un programme de paie, vous devez utiliser une structure de données comprenant des employés. Dans le langage Go, vous pouvez utiliser des structs afin de regrouper différents champs en vue de créer un enregistrement.
Dans le langage Go, un struct est un autre type de données qui peut contenir zéro, un ou plusieurs champs de types arbitraires, et les représenter comme une seule et même entité.
Dans cette section, nous allons découvrir pourquoi les structs sont essentiels et comment les utiliser.
Déclarer et initialiser un struct
Pour déclarer un struct, vous devez utiliser le mot clé struct
, ainsi que la liste des champs (avec leurs types) que vous souhaitez associer à votre nouveau type de données. Par exemple, pour définir un struct d’employé, vous pouvez utiliser le code suivant :
type Employee struct {
ID int
FirstName string
LastName string
Address string
}
Ensuite, vous pouvez déclarer une variable avec le nouveau type, comme vous le feriez pour d’autres types, de la façon suivante :
var john Employee
Et si vous souhaitez déclarer et initialiser une variable en même temps, vous pouvez le faire de la façon suivante :
employee := Employee{1001, "John", "Doe", "Doe's Street"}
Notez que vous devez spécifier une valeur pour chacun des champs de la structure. Cependant, cela peut parfois poser problème. Vous pouvez également être plus précis concernant les champs que vous souhaitez initialiser dans une structure :
employee := Employee{LastName: "Doe", FirstName: "John"}
Dans l’instruction précédente, remarquez que l’ordre dans lequel vous affectez des valeurs aux champs n’a pas d’importance. Cela n’a pas non plus d’importance si vous ne spécifiez pas de valeur pour un autre champ. Go affecte une valeur par défaut au champ en fonction de son type de données.
Pour accéder aux champs d’un struct, vous pouvez utiliser la notation par points (.
), comme dans l’exemple suivant :
employee.ID = 1001
fmt.Println(employee.FirstName)
Enfin, vous pouvez utiliser l’opérateur &
pour générer un pointeur vers le struct, comme le montre le code suivant :
package main
import "fmt"
type Employee struct {
ID int
FirstName string
LastName string
Address string
}
func main() {
employee := Employee{LastName: "Doe", FirstName: "John"}
fmt.Println(employee)
employeeCopy := &employee
employeeCopy.FirstName = "David"
fmt.Println(employee)
}
Quand vous exécutez le code précédent, vous obtenez la sortie suivante :
{0 John Doe }
{0 David Doe }
Notez que le struct devient mutable quand vous utilisez des pointeurs.
Incorporation des structs
Dans le langage Go, les structs permettent d’incorporer un struct dans un autre struct. Vous souhaiterez parfois ne pas répéter les mêmes opérations et réutiliser un struct commun. Par exemple, supposons que vous souhaitiez refactoriser le code précédent de manière à avoir un certain type de données pour un employé et un autre type pour un fournisseur. Vous pouvez avoir un struct Person
qui contient des champs communs, comme dans cet exemple :
type Person struct {
ID int
FirstName string
LastName string
Address string
}
Vous pouvez ensuite déclarer d’autres types qui incorporent un type Person
, comme un Employee
ou un Contractor
. Pour incorporer un autre struct, vous devez créer un nouveau champ, comme dans l’exemple suivant :
type Employee struct {
Information Person
ManagerID int
}
Toutefois, pour référencer un champ du struct Person
, vous devez inclure le champ Information
d’une variable employee, comme dans cet exemple :
var employee Employee
employee.Information.FirstName = "John"
Si vous refactorisez du code comme nous le faisons, cela entraînera l’arrêt de notre code. Vous pouvez également inclure un nouveau champ portant le même nom que celui du struct que vous incorporez, comme dans cet exemple :
type Employee struct {
Person
ManagerID int
}
Pour en avoir une démonstration, vous pouvez utiliser le code suivant :
package main
import "fmt"
type Person struct {
ID int
FirstName string
LastName string
Address string
}
type Employee struct {
Person
ManagerID int
}
type Contractor struct {
Person
CompanyID int
}
func main() {
employee := Employee{
Person: Person{
FirstName: "John",
},
}
employee.LastName = "Doe"
fmt.Println(employee.FirstName)
}
Remarquez que vous accédez au champ FirstName
à partir d’un struct Employee
sans avoir à spécifier le champ Person
. Cela est dû au fait que tous ses champs sont incorporés automatiquement. Toutefois, lorsque vous initialisez un struct, vous devez indiquer précisément le champ auquel vous souhaitez affecter une valeur.
Encoder et décoder des structs avec JSON
Enfin, vous pouvez utiliser des structs pour encoder et décoder des données au format JSON. Go offre une excellente prise en charge du format JSON, qui est déjà incluse dans les packages de bibliothèque standard.
Vous pouvez également effectuer des opérations telles que le renommage d’un champ du struct. Par exemple, supposons que vous ne souhaitiez pas que la sortie JSON affiche FirstName
mais simplement name
, ou que vous souhaitiez ignorer les champs vides. Vous pouvez utiliser des étiquettes de champ comme dans l’exemple suivant :
type Person struct {
ID int
FirstName string `json:"name"`
LastName string
Address string `json:"address,omitempty"`
}
Ensuite, pour encoder un struct au format JSON, vous devez utiliser la fonction json.Marshal
. Pour décoder une chaîne JSON en une structure de données, vous devez utiliser la fonction json.Unmarshal
. Voici un exemple qui rassemble tout ce que nous venons de voir, en encodant un tableau d’employés au format JSON et en décodant la sortie dans une nouvelle variable :
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
ID int
FirstName string `json:"name"`
LastName string
Address string `json:"address,omitempty"`
}
type Employee struct {
Person
ManagerID int
}
type Contractor struct {
Person
CompanyID int
}
func main() {
employees := []Employee{
Employee{
Person: Person{
LastName: "Doe", FirstName: "John",
},
},
Employee{
Person: Person{
LastName: "Campbell", FirstName: "David",
},
},
}
data, _ := json.Marshal(employees)
fmt.Printf("%s\n", data)
var decoded []Employee
json.Unmarshal(data, &decoded)
fmt.Printf("%v", decoded)
}
Quand vous exécutez le code précédent, vous obtenez la sortie suivante :
[{"ID":0,"name":"John","LastName":"Doe","ManagerID":0},{"ID":0,"name":"David","LastName":"Campbell","ManagerID":0}]
[{{0 John Doe } 0} {{0 David Campbell } 0}]