Comprendre les types de données en Go

introduction

Les types de données spécifient les types de valeurs que des variables particulières vont stocker lorsque vous écrivez un programme. Le type de données détermine également les opérations pouvant être effectuées sur les données.

Dans cet article, nous allons passer en revue les types de données importants natifs de Go. Il ne s’agit pas d’une enquête exhaustive sur les types de données, mais vous aidera à vous familiariser avec les options à votre disposition dans Go. Comprendre certains types de données de base vous permettra d’écrire un code plus clair et performant.

Contexte

Une façon de penser aux types de données consiste à examiner les différents types de données que nous utilisons dans le monde réel. Un exemple de données dans le monde réel sont les nombres: on peut utiliser des nombres entiers (0, 1, 2,…), des entiers (…, -1, 0, 1,…) et des nombres irrationnels (π), par exemple.

Habituellement, en mathématiques, nous pouvons combiner des nombres de différents types et obtenir une réponse. On peut vouloir ajouter 5 à π, par exemple:

5 + π

Nous pouvons soit garder l'équation comme réponse pour rendre compte du nombre irrationnel, soit arrondir π à un nombre avec un nombre abrégé de décimales, puis additionner les nombres:

5 + π = 5 + 3.14 = 8.14

Mais, si nous essayons d'évaluer des nombres avec un autre type de données, tel que des mots, les choses commencent à avoir moins de sens. Comment pourrions-nous résoudre l'équation suivante?

shark + 8

Pour les ordinateurs, chaque type de données est assez différent, comme les mots et les chiffres. En conséquence, nous devons faire attention à la manière dont nous utilisons des types de données variés pour attribuer des valeurs et à la manière dont nous les manipulons à travers des opérations.

Entiers

Comme en mathématiques, lesintegers en programmation informatique sont des nombres entiers qui peuvent être positifs, négatifs ou 0 (…, -1, 0, 1,…). Dans Go, un entier est appeléint. Comme pour les autres langages de programmation, vous ne devez pas utiliser de virgules avec des nombres de quatre chiffres ou plus, donc lorsque vous écrivez 1 000 dans votre programme, écrivez-le sous la forme1000.

Nous pouvons imprimer un entier de manière simple comme ceci:

fmt.Println(-459)
Output-459

Ou bien, nous pouvons déclarer une variable, qui dans ce cas est un symbole du nombre que nous utilisons ou manipulons, comme ceci:

var absoluteZero int = -459
fmt.Println(absoluteZero)
Output-459

Nous pouvons aussi faire des mathématiques avec des nombres entiers dans Go. Dans le bloc de code suivant, nous utiliserons l'opérateur d'affectation:= pour déclarer et instancier la variablesum:

sum := 116 - 68
fmt.Println(sum)
Output48

Comme le montre la sortie, l'opérateur mathématique- a soustrait l'entier68 de116, résultant en48. Vous en apprendrez plus sur la déclaration des variables dans la sectionDeclaring Data Types for Variables.

Les entiers peuvent être utilisés de nombreuses manières dans les programmes Go. Si vous continuez à vous familiariser avec Go, vous aurez de nombreuses occasions de travailler avec des nombres entiers et de développer vos connaissances de ce type de données.

Nombres à virgule flottante

Unfloating-point number ou unfloat est utilisé pour représenter desreal numbers qui ne peuvent pas être exprimés sous forme d'entiers. Les nombres réels incluent tous les nombres rationnels et irrationnels. De ce fait, les nombres à virgule flottante peuvent contenir une partie fractionnaire, telle que 9.0 ou -116.42. Pour pouvoir penser à un flottant dans un programme Go, il s’agit d’un nombre qui contient un point décimal.

Comme nous l'avons fait avec des nombres entiers, nous pouvons imprimer un nombre à virgule flottante d'une manière simple comme ceci:

fmt.Println(-459.67)
Output-459.67

Nous pouvons aussi déclarer une variable qui remplace un float, comme ceci:

absoluteZero := -459.67
fmt.Println(absoluteZero)
Output-459.67

Tout comme avec les nombres entiers, nous pouvons aussi faire des calculs mathématiques avec des flottants dans Go:

var sum = 564.0 + 365.24
fmt.Println(sum)
Output929.24

Avec les nombres entiers et les nombres à virgule flottante, il est important de garder à l'esprit que 3 ≠ 3.0, car 3 correspond à un entier, tandis que 3,0 correspond à un flottant.

Tailles des types numériques

Outre la distinction entre nombres entiers et flottants, Go propose deux types de données numériques qui se distinguent par la nature statique ou dynamique de leur taille. Le premier type est un typearchitecture-independent, ce qui signifie que la taille des données en bits ne change pas, quelle que soit la machine sur laquelle le code s'exécute.

La plupart des architectures système actuelles sont en 32 bits ou en 64 bits. Par exemple, vous développez peut-être un ordinateur portable Windows moderne, sur lequel le système d'exploitation s'exécute sur une architecture 64 bits. Toutefois, si vous développez un appareil comme une montre de fitness, vous pouvez utiliser une architecture 32 bits. Si vous utilisez un type indépendant de l'architecture commeint32, quelle que soit l'architecture pour laquelle vous compilez, le type aura une taille constante.

Le second type est un typeimplementation-specific. Dans ce type, la taille en bits peut varier en fonction de l'architecture sur laquelle le programme est construit. Par exemple, si nous utilisons le typeint, lorsque Go compile pour une architecture 32 bits, la taille du type de données sera de 32 bits. Si le programme est compilé pour une architecture 64 bits, la variable aura une taille de 64 bits.

En plus des types de données de tailles différentes, les types tels que les entiers sont également disponibles en deux types de base:signed etunsigned. Unint8 est un entier signé et peut avoir une valeur comprise entre -128 et 127. Unuint8 est un entier non signé et ne peut avoir qu'une valeur positive comprise entre 0 et 255.

Les plages sont basées sur la taille du bit. Pour les données binaires, 8 bits peuvent représenter un total de 256 valeurs différentes. Étant donné qu'un typeint doit prendre en charge les valeurs positives et négatives, un entier de 8 bits (int8) aura une plage de -128 à 127, pour un total de 256 valeurs possibles uniques.

Go a les types entiers suivants indépendants de l'architecture:

uint8       unsigned  8-bit integers (0 to 255)
uint16      unsigned 16-bit integers (0 to 65535)
uint32      unsigned 32-bit integers (0 to 4294967295)
uint64      unsigned 64-bit integers (0 to 18446744073709551615)
int8        signed  8-bit integers (-128 to 127)
int16       signed 16-bit integers (-32768 to 32767)
int32       signed 32-bit integers (-2147483648 to 2147483647)
int64       signed 64-bit integers (-9223372036854775808 to 9223372036854775807)

Les flotteurs et les nombres complexes existent également en différentes tailles:

float32     IEEE-754 32-bit floating-point numbers
float64     IEEE-754 64-bit floating-point numbers
complex64   complex numbers with float32 real and imaginary parts
complex128  complex numbers with float64 real and imaginary parts

Il existe également deux types de numéros d'alias, qui attribuent des noms utiles à des types de données spécifiques:

byte        alias for uint8
rune        alias for int32

Le but de l'aliasbyte est d'indiquer clairement quand votre programme utilise des octets comme mesure de calcul commune dans les éléments de chaîne de caractères, par opposition aux petits entiers non liés à la mesure des données d'octets. Même sibyte etuint8 sont identiques une fois le programme compilé,byte est souvent utilisé pour représenter des données de caractères sous forme numérique, alors queuint8 est censé être un nombre en votre programme.

L'aliasrune est un peu différent. Oùbyte etuint8 sont exactement les mêmes données, unrune peut être un octet ou quatre octets, une plage déterminée parint32. Unrune est utilisé pour représenter un caractère Unicode, alors que seuls les caractères ASCII peuvent être représentés uniquement par un type de donnéesint32.

De plus, Go possède les types suivants spécifiques à l'implémentation:

uint     unsigned, either 32 or 64 bits
int      signed, either 32 or 64 bits
uintptr  unsigned integer large enough to store the uninterpreted bits of a pointer value

La taille des types spécifiques à l'implémentation sera définie par l'architecture pour laquelle le programme est compilé.

Choisir des types de données numériques

Choisir la taille correcte a généralement plus à voir avec les performances de l'architecture cible pour laquelle vous programmez que la taille des données avec lesquelles vous travaillez. Cependant, sans avoir besoin de connaître les ramifications spécifiques de la performance de votre programme, vous pouvez suivre certaines de ces directives de base lors de vos débuts.

Comme indiqué précédemment dans cet article, il existe des types indépendants de l'architecture et des types spécifiques à l'implémentation. Pour les données entières, il est courant dans Go d'utiliser les types d'implémentation tels queint ouuint au lieu deint64 ouuint64. Cela se traduira généralement par la vitesse de traitement la plus rapide pour votre architecture cible. Par exemple, si vous utilisez unint64 et compilez vers une architecture 32 bits, il faudra au moins deux fois plus de temps pour traiter ces valeurs que des cycles CPU supplémentaires pour déplacer les données à travers l'architecture. Si vous utilisiez plutôt unint, le programme le définirait comme une taille 32 bits pour une architecture 32 bits, et serait beaucoup plus rapide à traiter.

Si vous savez que vous ne dépasserez pas une plage de tailles spécifique, le choix d’un type indépendant de l’architecture peut à la fois augmenter la vitesse et diminuer l’utilisation de la mémoire. Par exemple, si vous savez que vos données ne dépasseront pas la valeur de100 et ne seront qu'un nombre positif, alors choisir unuint8 rendra votre programme plus efficace car il nécessitera moins de mémoire.

Maintenant que nous avons examiné certaines des plages possibles pour les types de données numériques, voyons ce qui se passera si nous dépassons ces plages dans notre programme.

Débordement vs. Enrouler autour

Go a le potentiel à la fois deoverflow un nombre et dewraparound un nombre lorsque vous essayez de stocker une valeur plus grande que le type de données a été conçu pour stocker, selon que la valeur est calculée au moment de la compilation ou au moment de l'exécution. Une erreur de compilation survient lorsque le programme trouve une erreur alors qu'il tente de le générer. Une erreur d'exécution se produit après la compilation du programme, alors qu'il est en cours d'exécution.

Dans l'exemple suivant, nous définissonsmaxUint32 sur sa valeur maximale:

package main

import "fmt"

func main() {
    var maxUint32 uint32 = 4294967295 // Max uint32 size
    fmt.Println(maxUint32)
}

Il sera compilé et exécuté avec le résultat suivant:

Output4294967295

Si nous ajoutons1 à la valeur au moment de l'exécution, cela se terminera par0:

Output0

D'un autre côté, changeons le programme pour ajouter1 à la variable lorsque nous l'affectons, avant la compilation:

package main

import "fmt"

func main() {
    var maxUint32 uint32 = 4294967295 + 1
    fmt.Println(maxUint32)

}

Au moment de la compilation, si le compilateur peut déterminer qu'une valeur sera trop grande pour être contenue dans le type de données spécifié, il lèvera une erreuroverflow. Cela signifie que la valeur calculée est trop grande pour le type de données que vous avez spécifié.

Comme le compilateur peut déterminer qu'il dépassera la valeur, il générera une erreur:

Outputprog.go:6:36: constant 4294967296 overflows uint32

Comprendre les limites de vos données vous aidera à éviter d'éventuels bugs dans votre programme à l'avenir.

Maintenant que nous avons abordé les types numériques, voyons comment stocker les valeurs booléennes.

Booléens

Le type de donnéesboolean peut être l'une des deux valeurs, soittrue oufalse, et est défini commebool lors de sa déclaration comme type de données. Les booléens servent à représenter les valeurs de vérité associées à la branche logique des mathématiques, qui informe les algorithmes en informatique.

Les valeurstrue etfalse seront toujours avec unt etf minuscules respectivement, car ce sont des identifiants pré-déclarés dans Go.

De nombreuses opérations en mathématiques nous donnent des réponses qui évaluent vrai ou faux:

  • plus grand que

    • 500> 100 vrais

    • 1> 5 faux

  • moins que

    • 200 <400 vrais

    • 4 <2 faux

  • égal

    • 5 = 5 vrai

    • 500 = 400 faux

Comme avec les nombres, nous pouvons stocker une valeur booléenne dans une variable:

myBool := 5 > 8

On peut ensuite imprimer la valeur booléenne avec un appel à la fonctionfmt.Println():

fmt.Println(myBool)

Puisque5 n'est pas supérieur à8, nous recevrons la sortie suivante:

Outputfalse

Au fur et à mesure que vous écrivez plus de programmes dans Go, vous vous familiariserez avec le fonctionnement des booléens et la manière dont différentes fonctions et opérations évaluées àtrue ou àfalse peuvent changer le cours du programme.

Les cordes

Une chaîne est une séquence d'un ou plusieurs caractères (lettres, chiffres, symboles) pouvant être une constante ou une variable. Les chaînes existent entre guillemets arrière+\ + `ou guillemets doubles" dans Go et ont des caractéristiques différentes selon les guillemets que vous utilisez.

Si vous utilisez les guillemets, vous créez un littéral de chaîneraw. Si vous utilisez les guillemets doubles, vous créez un littéral de chaîneinterpreted.

Littéraux de chaîne bruts

Les chaînes de caractères brutes sont des séquences de caractères entre guillemets, souvent appelées ticks arrière. Dans les guillemets, tout caractère apparaîtra tel qu’il est affiché entre les guillemets arrières, à l’exception du caractère lui-même.

a := `Say "hello" to Go!`
fmt.Println(a)
OutputSay "hello" to Go!

En règle générale, les barres obliques inverses sont utilisées pour représenter les caractères spéciaux dans les chaînes. Par exemple, dans une chaîne interprétée, représenterait une nouvelle ligne dans une chaîne. Toutefois, les barres obliques inverses n'ont aucune signification particulière dans les littéraux de chaîne bruts:

a := `Say "hello" to Go!\n`
fmt.Println(a)

Comme la barre oblique inverse n'a pas de signification particulière dans un littéral de chaîne, elle affichera en fait la valeur de au lieu de créer une nouvelle ligne:

OutputSay "hello" to Go!\n

Les littéraux de chaîne brute peuvent également être utilisés pour créer des chaînes multilignes:

a := `This string is on
multiple lines
within a single back
quote on either side.`
fmt.Println(a)
OutputThis string is on
multiple lines
within a single back
quote on either side.

Dans les blocs de code précédents, les nouvelles lignes étaient reportées littéralement d’entrée en sortie.

Littéraux chaîne interprétés

Les littéraux de chaîne interprétés sont des séquences de caractères entre guillemets, comme dans"bar". À l'intérieur des guillemets, n'importe quel caractère peut apparaître, à l'exception des guillemets newline et non échappés. Pour afficher les guillemets dans une chaîne interprétée, vous pouvez utiliser la barre oblique inversée comme caractère d'échappement, comme suit:

a := "Say \"hello\" to Go!"
fmt.Println(a)
OutputSay "hello" to Go!

Vous utiliserez presque toujours des littéraux de chaîne interprétés, car ils autorisent les caractères d'échappement en leur sein. Pour plus d'informations sur l'utilisation des chaînes, consultezAn Introduction to Working with Strings in Go.

Cordes avec caractères UTF-8

UTF-8 est un schéma de codage utilisé pour coder des caractères de largeur variable sur un à quatre octets. Go prend en charge les caractères UTF-8 prêts à l'emploi, sans configuration, bibliothèques ou packages spéciaux. Les caractères romains tels que la lettreA peuvent être représentés par une valeur ASCII telle que le nombre 65. Cependant, avec des caractères spéciaux tels qu'un caractère international de, UTF-8 serait requis. Go utilise le type d'aliasrune pour les données UTF-8.

a := "Hello, 世界"

Vous pouvez utiliser le mot clérange dans une bouclefor pour indexer n'importe quelle chaîne dans Go, même une chaîne UTF-8. Les bouclesfor etrange seront couvertes plus en détail plus tard dans la série; pour l'instant, il est important de savoir que nous pouvons utiliser ceci pour compter les octets dans une chaîne donnée:

package main

import "fmt"

func main() {
    a := "Hello, 世界"
    for i, c := range a {
        fmt.Printf("%d: %s\n", i, string(c))
    }
    fmt.Println("length of 'Hello, 世界': ", len(a))
}

Dans le bloc de code ci-dessus, nous avons déclaré la variablea et lui avons attribué la valeurHello, 世界. Le texte affecté contient des caractères UTF-8.

Nous avons ensuite utilisé une boucle standardfor ainsi que le mot clérange. Dans Go, le mot-clérange indexera via une chaîne retournant un caractère à la fois, ainsi que l'index d'octet auquel se trouve le caractère dans la chaîne.

En utilisant la fonctionfmt.Printf, nous avons fourni une chaîne de format de%d: %s . %d est le verbe d'impression d'un chiffre (dans ce cas un entier), et%s est le verbe d'impression d'une chaîne. Nous avons ensuite fourni les valeurs dei, qui est l'indice actuel de la bouclefor, etc, qui est le caractère courant dans la bouclefor.

Enfin, nous avons imprimé toute la longueur de la variablea en utilisant la fonction intégréelen.

Plus tôt, nous avons mentionné qu'une rune est un alias pourint32 et peut être composée d'un à quatre octets. Le caractère prend trois octets à définir et l'index se déplace en conséquence lors de la sélection de la chaîne UTF-8. C'est la raison pour laquellei n'est pas séquentiel lorsqu'il est imprimé.

Output0: H
1: e
2: l
3: l
4: o
5: ,
6:
7: 世
10: 界
length of 'Hello, 世界':  13

Comme vous pouvez le constater, la longueur est supérieure au nombre de fois qu'il a fallu parcourir la chaîne.

Vous ne travaillerez pas toujours avec des chaînes UTF-8, mais lorsque vous l'êtes, vous comprendrez maintenant pourquoi ce sont des runes et pas un seulint32.

Déclaration de types de données pour les variables

Maintenant que vous connaissez les différents types de données primitifs, nous verrons comment affecter ces types à des variables dans Go.

Dans Go, on peut définir une variable avec le mot-clévar suivi du nom de la variable et du type de données souhaité.

Dans l'exemple suivant, nous déclarerons une variable appeléepi de typefloat64.

Le mot-clévar est la première chose déclarée:

var pi float64

Suivi du nom de notre variable,pi:

var pi float64

Et enfin le type de donnéesfloat64:

var pi float64

Nous pouvons également spécifier une valeur initiale, telle que3.14:

var pi float64 = 3.14

Go est une langue destatically typed. Statiquement, cela signifie que chaque instruction du programme est vérifiée au moment de la compilation. Cela signifie également que le type de données est lié à la variable, alors que dans les langages liés de manière dynamique, le type de données est lié à la valeur.

Par exemple, dans Go, le type est déclaré lors de la déclaration d'une variable:

var pi float64 = 3.14
var week int = 7

Chacune de ces variables pourrait être un type de données différent si vous les déclariez différemment.

Cela diffère d'un langage comme PHP, où le type de données est associé à la valeur:

$s = "sammy";         // $s is automatically a string
$s = 123;             // $s is automatically an integer

Dans le bloc de code précédent, le premier$s est une chaîne car la valeur"sammy" lui est attribuée et le second est un entier car il a la valeur123.

Ensuite, examinons des types de données plus complexes tels que les tableaux.

Tableaux

Unarray est une séquence ordonnée d'éléments. La capacité d'un tableau est définie au moment de la création. Une fois qu'un tableau a alloué sa taille, celle-ci ne peut plus être modifiée. Parce que la taille d'un tableau est statique, cela signifie qu'il n'alloue de la mémoire qu'une seule fois. Cela rend les tableaux assez rigides, mais augmente les performances de votre programme. Pour cette raison, les tableaux sont généralement utilisés lors de l'optimisation des programmes. LesSlices, abordés ensuite, sont plus flexibles et constituent ce que vous pourriez considérer comme des tableaux dans d'autres langues.

Les tableaux sont définis en déclarant la taille du tableau, puis le type de données avec les valeurs définies entre accolades{ }.

Un tableau de chaînes ressemble à ceci:

[3]string{"blue coral", "staghorn coral", "pillar coral"}

Nous pouvons stocker un tableau dans une variable et l'imprimer:

coral := [3]string{"blue coral", "staghorn coral", "pillar coral"}
fmt.Println(coral)
Output[blue coral staghorn coral pillar coral]

Comme mentionné précédemment, les tranches ressemblent aux tableaux, mais sont beaucoup plus flexibles. Jetons un coup d’œil à ce type de données mutable.

Les tranches

Unslice est une séquence ordonnée d'éléments dont la longueur peut changer. Les tranches peuvent augmenter leur taille de manière dynamique. Lorsque vous ajoutez de nouveaux éléments à une tranche, si celle-ci ne dispose pas de suffisamment de mémoire pour stocker les nouveaux éléments, elle demandera plus de mémoire au système, si nécessaire. Puisqu'une tranche peut être développée pour ajouter plus d'éléments si nécessaire, elle est plus couramment utilisée que les tableaux.

Les tranches sont définies en déclarant le type de données précédé d'un crochet ouvrant et fermant[] et ayant des valeurs entre accolades{ }.

Une tranche d'entiers ressemble à ceci:

[]int{-3, -2, -1, 0, 1, 2, 3}

Une tranche de flotteurs ressemble à ceci:

[]float64{3.14, 9.23, 111.11, 312.12, 1.05}

Une tranche de ficelle ressemble à ceci:

[]string{"shark", "cuttlefish", "squid", "mantis shrimp"}

Définissons notre tranche de chaînes commeseaCreatures:

seaCreatures := []string{"shark", "cuttlefish", "squid", "mantis shrimp"}

Nous pouvons les imprimer en appelant la variable:

fmt.Println(seaCreatures)

La sortie ressemblera exactement à la liste que nous avons créée:

Output[shark cuttlefish squid mantis shrimp]

Nous pouvons utiliser le mot-cléappend pour ajouter un élément à notre tranche. La commande suivante ajoutera la valeur de chaîne deseahorse à la tranche:

seaCreatures = append(seaCreatures, "seahorse")

Vous pouvez vérifier qu'il a été ajouté en l'imprimant:

fmt.Println(seaCreatures)
Output[shark cuttlefish squid mantis shrimp seahorse]

Comme vous pouvez le constater, si vous devez gérer une taille inconnue d’éléments, une tranche sera beaucoup plus polyvalente qu’un tableau.

Maps

Lemap est le hachage ou le type de dictionnaire intégré de Go. Les cartes utilisentkeys etvalues comme une paire pour stocker les données. Ceci est utile en programmation pour rechercher rapidement des valeurs à l'aide d'un index ou, dans ce cas, d'une clé. Par exemple, vous souhaiterez peut-être conserver une carte des utilisateurs, indexée par leur ID utilisateur. La clé serait l'ID utilisateur et l'objet utilisateur serait la valeur. Une carte est construite à l'aide du mot-clémap suivi du type de données clé entre crochets[ ], suivi du type de données valeur et des paires valeur / clé entre accolades.

map[key]value{}

Généralement utilisée pour stocker des données liées, telles que les informations contenues dans un identifiant, une carte ressemble à ceci:

map[string]string{"name": "Sammy", "animal": "shark", "color": "blue", "location": "ocean"}

Vous remarquerez qu'en plus des accolades, il y a aussi des deux points sur toute la carte. Les mots à la gauche des deux points sont les clés. Les clés peuvent être de n'importe quel typecomparable dans Go. Les types comparables sont des types primitifs commestrings,ints, etc. Un type primitif est défini par le langage et n'est pas construit en combinant d'autres types. Bien qu'ils puissent être des types définis par l'utilisateur, il est recommandé de les garder simples afin d'éviter les erreurs de programmation. Les clés du dictionnaire ci-dessus sont:name,animal,color etlocation.

Les mots à la droite des deux points sont les valeurs. Les valeurs peuvent être composées de n'importe quel type de données. Les valeurs du dictionnaire ci-dessus sont:Sammy,shark,blue etocean.

Stockons la carte dans une variable et l’imprimons:

sammy := map[string]string{"name": "Sammy", "animal": "shark", "color": "blue", "location": "ocean"}
fmt.Println(sammy)
Outputmap[animal:shark color:blue location:ocean name:Sammy]

Si nous voulons isoler la couleur de Sammy, nous pouvons le faire en appelantsammy["color"]. Imprimons cela:

fmt.Println(sammy["color"])
Outputblue

Comme les cartes offrent des paires clé-valeur pour le stockage de données, elles peuvent constituer des éléments importants de votre programme Go.

Conclusion

À ce stade, vous devriez avoir une meilleure compréhension de certains des principaux types de données que vous pouvez utiliser dans Go. Chacun de ces types de données deviendra important à mesure que vous développez des projets de programmation dans le langage Go.

Une fois que vous avez une solide compréhension des types de données disponibles dans Go, vous pouvez apprendreHow To Convert Data Types afin de modifier vos types de données en fonction de la situation.