Silex v0.47.1 / Docs Source canonique ↗

Sélectionner une valeur avec match

Un enum déclare un ensemble fermé de variantes. Une variante peut transporter des valeurs associées.

enum Connection {
    waiting
    connected(str)
    closed(str)
}

func main() {
    let pending = Connection.waiting
    let active = Connection.connected("serveur")
    print(pending != active)
}

Une variante sans valeur associée est déjà une valeur et n'a pas besoin de parenthèses. L'ancienne forme Connection.waiting() reste acceptée. Une variante avec valeurs reste une construction et exige ses parenthèses.

Le mot in est contextuel dans les déclarations d'enum, les accès de variantes et les branches de match. Un nom intentionnel comme Easing.in reste donc disponible.

Produire une valeur avec match

func describe(connection:Connection) str {
    return match connection {
        waiting => "attente"
        connected(name) => name
        closed(reason) => reason
    }
}

Le sujet est évalué une fois et n'est pas consommé. Chaque variante apparaît exactement une fois et chaque branche produit exactement le même type.

Une expression entre parenthèses reste une branche concise, même lorsqu'elle occupe plusieurs lignes :

let predicted = match condition {
    true => (x * 10.0 / 2.0 + 0.5)
    else => 0.0
}

Choisir selon des conditions ordonnées

Omettez le sujet pour écrire une suite de conditions. Le compilateur les évalue de haut en bas et sélectionne la première qui produit true :

let category = match {
    score >= 16 => "excellent"
    score >= 10 => "admis"
    else => "insuffisant"
}

Chaque condition doit produire un bool. Cette forme exige toujours else, qui garantit une valeur ou une action lorsque toutes les conditions échouent.

Écrivez _ pour ignorer volontairement une valeur associée. Il occupe toujours sa position mais ne déclare aucune variable ; la valeur reste possédée par l'enum et suit sa durée de vie ordinaire. let _ et var _ sont invalides. Seule une branche else absorbe toutes les variantes restantes.

Filtrer une variante avec une garde

let category = match token {
    integer(value, _) if value < 0 => "négatif"
    integer(value, _) if value == 0 => "zéro"
    integer(_, _) => "positif"
    identifier(name, _) if name == "self" => "réservé"
    identifier(_, _) => "nom"
    else => "autre"
}

La garde s'exécute seulement après la correspondance de sa variante, voit les liaisons du motif et doit produire un bool. Une garde fausse poursuit avec la branche suivante.

Une branche gardée ne prouve jamais l'exhaustivité : chaque variante demande finalement une branche non gardée, sauf si else couvre les cas restants. Une branche non gardée rend inatteignable toute branche ultérieure de la même variante.

Exécuter des instructions dans les branches

match connection {
    waiting => { print("attente") }
    connected(name) => { print(name) }
    closed(reason) => { print(reason) }
}

Lorsqu'un match est une instruction, une branche courte peut aussi appeler directement une fonction :

match condition {
    true => accept()
    else => reject()
}

Une branche expression d'un match instruction doit être un appel, une cascade, une propagation avec try ou un autre match. Les blocs et ces branches courtes peuvent être mélangés et ne continuent jamais implicitement vers la branche suivante.

Calculer une valeur dans un bloc

Terminez un bloc de branche par yield lorsque son résultat demande plusieurs instructions :

let predicted = match condition {
    true => {
        var result = 0.0
        result += x * 10.0
        result /= 2.0
        yield result + 0.5
    }
    else => 0.0
}

Dans un match utilisé comme valeur, chaque bloc de branche doit se terminer directement par yield expression. Une branche expression voisine reste valide ; toutes les valeurs produites doivent avoir exactement le même type. return termine toujours la fonction englobante, tandis que yield fournit la valeur de la branche au match producteur le plus proche.

Les match peuvent donc être imbriqués sans ambiguïté :

let value = match outer {
    true => {
        yield match inner {
            true => { yield 1 }
            else => 0
        }
    }
    else => -1
}

Le yield 1 appartient au match inner; le yield match inner fournit ensuite son résultat au match outer.

Sélectionner un littéral scalaire

match accepte aussi un sujet bool, entier ou str. Chaque motif est un littéral du même type que le sujet ; un littéral entier reçoit le type entier du sujet et doit tenir dans son intervalle.

func status(code:int) str {
    return match code {
        200 => "ok"
        404 => "introuvable"
        else => "autre"
    }
}

Les branches sont essayées dans leur ordre et la première correspondance dont la garde réussit est sélectionnée. Le sujet est évalué une seule fois. Une branche non gardée rend inatteignable tout motif identique placé après elle ; deux branches non gardées ne peuvent pas répéter le même littéral.

Un match entier ou str exige une branche else. Un match booléen peut l'omettre lorsque true et false possèdent chacun une branche non gardée. Les branches ne continuent jamais implicitement dans la suivante : utilisez un bloc dans chaque branche pour exécuter des instructions.

Associer une valeur brute

enum Direction:int {
    north = 1
    south = -2
}

let code:int = Direction.north.raw_value

Un enum brut emploie int ou str. Chaque variante fournit un littéral unique. L'enum et son type brut ne se convertissent jamais implicitement l'un vers l'autre.

Comparer et copier

== compare d'abord la variante active, puis récursivement toutes ses valeurs associées. Deux variantes différentes sont inégales ; != inverse ce résultat. Les valeurs associées doivent elles-mêmes être comparables : les structures comparent leurs champs et les classes leur identité partagée. Un enum brut compare toujours sa variante, pas implicitement sa raw_value.

La copie d'un enum copie compositionnellement le contenu de sa variante active. Si ce contenu possède un drop, chaque copie possède son propre contenu et détruit seulement la variante active.

Les enums génériques sont traités avec les types génériques.

Revenir aux types de données · Retourner une erreur récupérable