web-dev-qa-db-fra.com

Certains et aucun, quels sont-ils?

En programmant quelques petits exercices pour débutants essayant de s'habituer à Rust, je suis tombé sur une sortie que je ne comprends pas en utilisant Vec::get. Voici le code:

fn main() {
    let command = [('G', 'H'), ('H', '5')];

    for i in 0..3 {
        print!(" {} ", i);
        println!("{:?}", command.get(i));
    }
}

la sortie est

0 Some(('G', 'H'))
1 Some(('H', '5'))
2 None

J'ai déjà essayé Haskell, et je veux dire par là que j'ai regardé un site de tutoriel pendant 10 minutes et que je suis retourné en C++, mais je me souviens avoir lu quelque chose sur Some et None pour Haskell. J'ai été surpris de voir ça ici à Rust. Quelqu'un pourrait-il expliquer pourquoi .get() renvoie Some ou None?

43
Syntactic Fructose

La signature de get (pour les tranches, pas Vec, puisque vous utilisez un tableau/tranche) est

fn get(&self, index: usize) -> Option<&T>

Autrement dit, il retourne un Option , qui est une énumération définie comme

pub enum Option<T> {
    None,
    Some(T),
}

None et Some sont les variantes de l'énumération, c'est-à-dire une valeur de type Option<T> peut être soit un None, soit un Some contenant une valeur de type T.

C'est la même chose que le noyau data Maybe a = Nothing | Just a tapez Haskell; les deux représentent une valeur facultative, c'est soit là (Some/Just), soit ce n'est pas (None/Nothing).

Ces types sont souvent utilisés pour représenter l'échec lorsqu'il n'y a qu'une seule possibilité pour laquelle quelque chose a échoué, par exemple, .get utilise Option pour donner un accès au tableau vérifié par les limites de type sécurisé: il renvoie None (c'est-à-dire aucune donnée) lorsque l'index est hors limites, sinon il renvoie un Some contenant le pointeur demandé.

37
huon

command n'est pas un vecteur (tapez Vec<T>), c'est un tableau de taille fixe (tapez [(char, char); 2] dans votre cas), et les tableaux sont automatiquement empruntés en tranches (vues en tableaux), vous pouvez donc utiliser toutes les méthodes définies sur les tranches, y compris get :

Renvoie l'élément d'une tranche à l'index donné, ou None si l'index est hors limites.

Le comportement est assez évident: quand un index donné est valide, il retourne Some avec l'élément sous cet index, sinon il retourne None.

Il existe une autre façon d'accéder aux éléments d'une tranche - l'opérateur d'indexation, qui devrait vous être familier:

let nums = [1, 2, 3];
let x = nums[1];

Il renvoie directement l'élément de la tranche, mais il échouera à la tâche en cours si l'index est hors limites:

fn main() {
    let x = [1, 2];
    for i in 0..3 {
        println!("{}", x[i]);
    }
}

Ce programme échoue:

% ./main2
1
2
task '<main>' failed at 'index out of bounds: the len is 2 but the index is 2', main2.rs:4

get() la méthode est nécessaire pour plus de commodité; il vous évite de vérifier à l'avance si l'index donné est valide.

Si vous ne savez pas ce que sont réellement Some et None et pourquoi ils sont nécessaires en général, vous devriez lire le officieltutoriel , il l'explique car c'est un concept très basique.

6
Vladimir Matveev

Considérez Some et None comme la manière canonique "sûre" de contourner le fait que la langue Rust ne prend pas en charge une utilisation "sûre" de NULL pointeurs. Comme la longueur de votre Vec est de 3 et que vous n'avez spécifié que deux paires, la troisième paire est effectivement NULL; au lieu de renvoyer NULL, il renvoie None.

Rust fournit des garanties de sécurité en nous forçant au moment de la compilation, via Some/None, à toujours faire face à la possibilité de None d'être retourné.

4
John Hinrichsen