Como converter & char para & str em Rust [duplicado]

Oct 19 2020

Dado um argumento & [char], que suponho ser um ou mais decimais em hexadecimal, estou tentando chamar from_str_radix para convertê-lo em bytes. No entanto, from_str_radix espera & str não & char. Existe uma maneira de converter cada & char em & 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;
}

Respostas

1 asmmo Oct 20 2020 at 05:06

Eu acho que isso vai funcionar conforme o esperado

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() é uma fatia da string gerada que consiste em um caractere.

Jmb Oct 20 2020 at 07:16

Você pode evitar alocações extras fazendo você mesmo a conversão:

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;

Além da verificação de erros se você não puder garantir que char é um dígito hexadecimal válido.

Observe, entretanto, que isso (assim como seu código original) converterá cada caractere individualmente. Então, se você chamar com "1a", bytesconterá [0x01, 0x0a]e não [0x1a] .

AngelicosPhosphoros Oct 20 2020 at 06:48

Um pouco mais rápido:

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, se você não se importa com o uso de memória extra e dependência de pull :

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: Corrigido erro no primeiro código cortado (esqueci, que um byte é codificado por 1 char). Esse tipo de erro é a razão pela qual você deve usar dependência em vez de codificar a própria solução, já que o crate é testado muito melhor.