Como faço para converter um vetor de bytes (u8) em uma string

94

Estou tentando escrever um cliente TCP / IP simples em Rust e preciso imprimir o buffer que obtive do servidor.

Como faço para converter um Vec<u8>(ou a &[u8]) em um String?

Athabaska Dick
fonte

Respostas:

98

Para converter uma fatia de bytes em uma fatia de string (assumindo uma codificação UTF-8):

use std::str;

//
// pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error>
//
// Assuming buf: &[u8]
//

fn main() {

    let buf = &[0x41u8, 0x41u8, 0x42u8];

    let s = match str::from_utf8(buf) {
        Ok(v) => v,
        Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
    };

    println!("result: {}", s);
}

A conversão está em vigor e não requer uma alocação. Você pode criar um a Stringpartir da fatia da string, se necessário, chamando .to_owned()a fatia da string ( outras opções estão disponíveis ).

A referência da biblioteca para a função de conversão:

gavinb
fonte
Você pode querer acrescentar que isso é possível porque Vec força as fatias
torkleyy
embora o código de exemplo não use realmente um vetor :-)
Andrew Mackenzie
Embora seja verdade que from_utf8não aloca, vale a pena mencionar que é necessário verificar os dados para validar a correção do utf-8. Portanto, esta não é uma operação O (1) (o que se pode pensar a princípio)
Zargony
64

Eu prefiro String::from_utf8_lossy:

fn main() {
    let buf = &[0x41u8, 0x41u8, 0x42u8];
    let s = String::from_utf8_lossy(buf);
    println!("result: {}", s);
}

Ele transforma bytes UTF-8 inválidos em e, portanto, nenhum tratamento de erro é necessário. É bom para quando você não precisa disso e eu quase não preciso. Você realmente obtém um Stringcom isso. Isso deve tornar a impressão do que você está obtendo do servidor um pouco mais fácil.

Às vezes, você pode precisar usar o into_owned()método, pois é clone na gravação.

Bjorn
fonte
3
Muito obrigado pela into_owned()sugestão! Era exatamente o que eu procurava (isso faz com que seja um próprio Stringque você pode retornar como valor de retorno de um método, por exemplo).
Per Lundberg
48

Se você realmente tem um vetor de bytes ( Vec<u8>) e deseja converter para um String, o mais eficiente é reutilizar a alocação com String::from_utf8:

fn main() {
    let bytes = vec![0x41, 0x42, 0x43];
    let s = String::from_utf8(bytes).expect("Found invalid UTF-8");
    println!("{}", s);
}
Shepmaster
fonte
2
Obrigado! Por que as outras duas respostas ignoraram a pergunta?
Jehan
1
@Jehan porque as pessoas geralmente não são boas em fazer perguntas, especialmente quando são novas no idioma. Rust faz uma distinção entre um array , um slice e a Vec, mas os novatos não conhecem as diferenças. No entanto, certifique-se de votar a favor de todas as perguntas e respostas que sejam úteis.
Shepmaster
Observe que, conforme mencionado por @Bjorn Tipling, você pode usar String::from_utf8_lossyaqui, então não precisa da chamada expect.
James Ray
2
Edit: Observe que, conforme mencionado por @Bjorn Tipling, você pode pensar que pode usar em String::from_utf8_lossyvez disso aqui, então você não precisa da expectchamada, mas a entrada para isso é uma fatia de bytess ( &'a [u8]). OTOH, há também from_utf8_unchecked. "Se você tem certeza que a fatia byte é válido UTF-8, e você não quer incorrer a sobrecarga da conversão, há uma versão insegura desta função [ from_utf8_lossy], from_utf8_uncheckedque tem o mesmo comportamento, mas ignora os cheques. "
James Ray
Observe que você pode usar &vec_of_bytespara converter de volta em uma fatia de bytes, conforme listado nos exemplos de from_utf8_lossy. doc.rust-lang.org/std/string/…
James Ray