web-dev-qa-db-fra.com

Pourquoi la conversion de type de u64 en usize est-elle autorisée en utilisant `as` mais pas` De`?

La première conversion utilisant 'en tant que' compile, mais la seconde utilisant le caractère 'De' ne le fait pas:

fn main() {
    let a: u64 = 5;
    let b = a as usize;
    let b = usize::from(a);
}

En utilisant Rust 1.22.1, j'obtiens l'erreur suivante:

error[E0277]: the trait bound `usize: std::convert::From<u64>` is not satisfied
 --> src/main.rs:4:13
  |
4 |     let b = usize::from(a);
  |             ^^^^^^^^^^^ the trait `std::convert::From<u64>` is not implemented for `usize`
  |
  = help: the following implementations were found:
            <usize as std::convert::From<u8>>
  = note: required by `std::convert::From::from`

Quand je remplace u64 par u8, il n'y a plus d'erreur. D'après le message d'erreur, je comprends que le trait From est implémenté uniquement pour u8, mais pas pour les autres types d'entiers.

S'il y a une bonne raison à cela, alors pourquoi la conversion utilisant 'as' ne devrait-elle pas échouer non plus?

9
Kağan Kayal

Les conversions as sont fondamentalement différentes des conversions From. Les conversions From sont "simpleet safe" alors que les conversions as sont purement "safe". Lorsqu’on considère les types numériques, les conversions From n’existent que lorsque la sortie est garantie comme le identique _, c’est-à-dire qu’il n’ya aucune perte d’informations (pas de troncature ni de flou, ni de précision). as castes, cependant, n'ont pas cette limitation.

Citant les docs, 

La taille de [usize] est "le nombre d'octets nécessaires pour référencer un emplacement en mémoire. Par exemple, sur une cible 32 bits, il s'agit de 4 octets et sur une cible 64 bits, de 8 octets". 

Étant donné que la taille dépend de l'architecture cible et ne peut pas être déterminée avant la compilation, rien ne garantit qu'une conversion From entre un type numérique et usize est possible. Cependant, une distribution as fonctionnera toujours selon les règles listées ici .

Par exemple, sur un système 32 bits, usize est équivalent à u32. Etant donné qu'une usize est inférieure à un u64, il peut y avoir une perte d'informations (troncature) lors de la conversion d'un u64 en un usize et par conséquent, une conversion From ne peut pas exister. Cependant, il est toujours garanti que la taille de usize sera d'au moins 8 bits et qu'une conversion de u8 à usizeFrom existera toujours.

10
EvilTak

Comme déjà mentionné, la conversion d'une valeur de 64 bits en une usize peut provoquer une troncature; vous risquez de perdre des données si une usize est de 16 ou 32 bits.

Les conversions susceptibles d’être mises en échec sont couvertes par le trait instable TryFrom :

#![feature(try_from)]

use std::convert::TryFrom;

fn main() {
    let a: u64 = 5;
    let b = a as usize;
    let b = usize::try_from(a);
}

Voir également:

1
Shepmaster