Comment convertir & char en & str dans Rust [duplicate]

Oct 19 2020

Étant donné un argument & [char], que je suppose est une ou plusieurs décimales en hexadécimal, j'essaie d'appeler from_str_radix pour le convertir en octets. Cependant, from_str_radix attend & str pas & char. Existe-t-il un moyen de convertir chaque & char en & str?

fn convertCharsToBytes(args: &[char]) -> std::vec::Vec<u8> {
    let mut bytes:Vec<u8> = Vec::new();
    for arg in args {
        let byte = u8::from_str_radix(arg, 16); //arg here is invalid as it is a &char, not a &str
        match byte {
            Ok(value) => bytes.push(value),
            Err(error) => {}
        }
    }
    println!("{:?}", bytes);
    return bytes;
}

Réponses

1 asmmo Oct 20 2020 at 05:06

Je pense que cela fonctionnera comme prévu

fn convertCharsToBytes(args: &[char]) -> std::vec::Vec<u8> {
    let mut bytes:Vec<u8> = Vec::new();
    for arg in args {
        let byte = u8::from_str_radix(&arg.to_string(), 16);
        match byte {
            Ok(value) => bytes.push(value),
            Err(error) => ()
        }
    }
    println!("{:?}", bytes);
    return bytes;
}

&arg.to_string() est une tranche de la chaîne générée qui se compose d'un caractère.

Jmb Oct 20 2020 at 07:16

Vous pouvez éviter des allocations supplémentaires en effectuant vous-même la conversion:

let byte = if char > 'a' { char as u32 - 'a' as u32 }
           else if char > 'A' { char as u32 - 'A' as u32 }
           else { char as u32 - '0' as u32 } as u8;

De plus, la vérification des erreurs si vous ne pouvez pas garantir que char est un chiffre hexadécimal valide.

Notez cependant que cela (ainsi que votre code d'origine) convertira chaque caractère individuellement. Donc, si vous l'appelez avec "1a", alors bytescontiendra [0x01, 0x0a]et non [0x1a] .

AngelicosPhosphoros Oct 20 2020 at 06:48

Légèrement plus rapide:

fn convertCharsToBytes(args: &[char]) -> std::vec::Vec<u8> {
    // E.g. 17 is encoded as 0x11 but 10 as 0x0A
    // So bytes are always encoded using 2 symbols
    assert_eq!(args.len()%2, 0, "Hexes length must be even!");
    let mut bytes:Vec<u8> = Vec::with_capacity(args.len()/2);
    // To reuse allocation instead calling to_string on every iteration
    let mut string = String::new();
    for &num in args.chunks_exact(2) {
        // To eliminate bounds checks in indexing
        // Maybe in future chunks_exact would return &[T;2] instead of &[T]
        // but it is inaccessible before const generics
        assert_eq!(num.len()==2);
        string.clear();
        string.push(num[0]);
        string.push(num[1]);
        let byte = u8::from_str_radix(&string, 16);
        match byte {
            Ok(value) => bytes.push(value),
            Err(_) => panic!("Invalid hex {}!", &string),
        }
    }
    println!("{:?}", bytes);
    return bytes;
}

Ou, si vous ne vous souciez pas de l'utilisation de la mémoire supplémentaire O (n) et de l'extraction de la dépendance :

fn convertCharsToBytes(args: &[char]) -> std::vec::Vec<u8> {
    let s: String = args.iter().collect();
    let bytes = hex::decode(&s).expect("Failed to parse hex");
    println!("{:?}", bytes);
    return bytes;
}

UPD: Correction d'une erreur dans le premier code extrait (j'ai oublié, qu'un octet est codé par 1 caractère). Ce type d'erreurs est la raison pour laquelle vous devriez utiliser la dépendance au lieu de coder votre propre solution, car crate est beaucoup mieux testé.