Menu

Les shapes en Zero : définir des enregistrements à la struct

Les shapes sont les types produit à la struct de Zero. Voici comment les déclarer, construire des valeurs, lire des champs et les passer à travers des fonctions — avec des exemples tirés des sources officielles.

Cette page contient des éditeurs exécutables — modifiez, exécutez et voyez la sortie instantanément.

Déclarer un shape

Un shape est un type d'enregistrement avec des champs nommés et typés :

shape Point {
    x: i32,
    y: i32,
}

Les pièces :

  • shape introduit la déclaration.
  • Point est le nom du type.
  • Les accolades enferment une liste de champs, chacun en nom: Type.

Cette déclaration ajoute un nouveau type appelé Point à la portée courante. Partout où vous pouvez utiliser un type intégré comme i32, vous pouvez aussi maintenant utiliser Point.

Construire une valeur de shape

Créez une instance avec une expression de littéral de struct :

let point = Point { x: 40, y: 2 }

Le littéral nomme le shape et affecte chaque champ. Chaque champ doit être présent — Zero ne met pas silencieusement à zéro ou à null les champs manquants. Si vous en oubliez un, le compilateur vous le dit :

{
    "code": "FLD002",
    "message": "missing field: y",
    "line": 4
}

(Le code d'erreur exact peut varier ; le principe « pas de valeurs par défaut implicites » est la constante.)

Vous pouvez lire ou annoter le type explicitement si vous voulez qu'il soit visible :

let point: Point = Point { x: 40, y: 2 }

Lire les champs

L'accès aux champs utilise la syntaxe pointée :

let point = Point { x: 40, y: 2 }
let xVal  = point.x
let yVal  = point.y

point.x lit le champ x. Il n'y a pas de méthode get_x() — les champs sont de la donnée pure.

Un exemple complet

Voici l'exemple canonique point.0 du dépôt du langage — cliquez sur Run pour l'essayer :

Lisez-le du haut vers le bas :

  1. Déclarez un shape Point avec deux champs i32.
  2. Définissez une fonction sum qui prend un Point et retourne la somme de ses champs.
  3. Dans main, construisez un Point, appelez sum, et comparez le résultat.

Trois étapes, trois idées liées aux shapes (déclarer, construire, accéder), et un effet — le check world.out.write(...) à la fin. Remarquez que sum ne touche pas World. C'est une fonction pure sur des données, et la signature le rend évident.

Shapes avec des champs imbriqués

Un shape peut contenir des valeurs de n'importe quel type, y compris d'autres shapes :

shape Range {
    start: i32,
    end: i32,
}

shape Segment {
    label: String,
    range: Range,
}

let seg = Segment {
    label: "warmup",
    range: Range { start: 0, end: 10 },
}

L'accès aux champs s'enchaîne comme prévu :

let len = seg.range.end - seg.range.start

Shapes génériques

Quand les champs d'un shape doivent être polymorphes en type, déclarez des paramètres de type entre chevrons :

shape Pair<T, U> {
    left: T,
    right: U,
}

Les instances fixent les paramètres à des types concrets :

let intBytePair: Pair<i32, u8> = Pair { left: 40, right: 2_u8 }
let words: Pair<String, String> = Pair { left: "hello", right: "world" }

Un alias de type peut raccourcir une paramétrisation courante :

type BytePair = Pair<u8, u8>

let bytes: BytePair = Pair { left: 1_u8, right: 2_u8 }

Generics couvre les paramètres de type plus en profondeur — y compris sur les fonctions, pas seulement sur les shapes.

Ce que les shapes ne sont pas

Quelques choses qu'on pourrait attendre d'une « struct » dans un autre langage que les shapes n'incluent délibérément pas :

  • Pas de méthodes. Une déclaration de shape, c'est juste de la donnée. Le comportement vit dans des fonctions libres qui prennent le shape en paramètre. Cela reflète la même séparation entre données et effets que vous voyez dans les fonctions.
  • Pas d'héritage. Les shapes n'étendent pas d'autres shapes. Si vous voulez une structure partagée, factorisez-la dans un champ commun ou construisez un type somme avec choice.
  • Pas de constructeurs ou destructeurs implicites. La construction, c'est l'expression de littéral de struct. Le nettoyage est explicite — quand la bibliothèque standard expose des ressources qui ont besoin d'être libérées, ça passe par des APIs façon capacité plutôt que par un RAII caché.
  • Pas de champs privés. Tous les champs d'un shape sont accessibles au code qui peut voir le type du shape. La visibilité est au niveau du type, pas du champ.

Le motif est : les shapes sont des types d'enregistrement simples et prévisibles, et vous construisez tout le reste à partir d'eux.

Quand utiliser un shape vs. un choice

Petit guide :

  • Utilisez un shape quand une valeur a tous ces champs ensemble. Un Point a toujours à la fois un x et un y.
  • Utilisez un choice quand une valeur est l'une parmi plusieurs alternatives. Un Result est soit un ok soit un err.
  • Utilisez un enum quand les alternatives ne portent aucune donnée supplémentaire — ce sont juste des étiquettes. Jours de la semaine, états simples.

Ces trois briques — shape (et), choice (ou), enum (ou sans charge utile) — couvrent presque tous les besoins de modélisation de données.

La suite : les génériques

Vous avez vu Pair<T, U> apparaître au passage. Le prochain document, generics, explique comment les paramètres de type fonctionnent sur les shapes et les fonctions, y compris les motifs qui apparaissent partout dans la bibliothèque standard de Zero.

Questions fréquentes

Qu'est-ce qu'un shape en Zero ?

Un shape est le type produit à la struct de Zero — un enregistrement nommé avec des champs typés. Vous le déclarez avec shape Name { field1: T1, field2: T2 }, construisez des valeurs avec Name { field1: v1, field2: v2 }, et lisez les champs avec la syntaxe pointée (value.field1). Les shapes sont la brique de base pour modéliser des données structurées.

Comment créer une valeur de shape ?

Utilisez une expression de littéral de struct qui nomme le shape et affecte chaque champ : let point = Point { x: 40, y: 2 }. Chaque champ doit être renseigné — Zero ne met pas silencieusement des valeurs par défaut sur les champs manquants. L'ordre des champs dans le littéral n'a pas à coller à celui de la déclaration.

En quoi un shape diffère-t-il d'une classe ?

Un shape est de la donnée pure — il a des champs, mais pas de méthodes, pas d'héritage, pas de constructeurs implicites. Les fonctions qui opèrent sur un shape le prennent explicitement en paramètre. Cette séparation garde le langage petit et rend prévisible le coût de construire ou copier un shape, sans vtables ou destructeurs cachés.

Les shapes peuvent-ils être génériques en Zero ?

Oui. Déclarez des paramètres de type entre chevrons : shape Pair<T, U> { left: T, right: U }. Les instances fixent ces paramètres : Pair<i32, u8>. Les shapes génériques apparaissent partout dans la bibliothèque standard — Maybe<T>, Span<T>, etc., sont tous des shapes ou types somme génériques bâtis sur la même idée.

Les shapes sont-ils copiés ou référencés quand on les passe à des fonctions ?

Le modèle mental par défaut pour les shapes est le passage par valeur — l'appelé voit sa propre copie logique des données, pas une référence dans la liaison de l'appelant. Le modèle mémoire exact en Zero pré-1.0 évolue encore (vous verrez ref et mutref dans les exemples de la bibliothèque standard pour des types de référence explicites). Pour la plupart du code applicatif, considérez les paramètres de shape comme des entrées par valeur.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER