Jak przekonwertować wektor bajtów (u8) na ciąg

99

Próbuję napisać prostego klienta TCP / IP w Rust i muszę wydrukować bufor, który otrzymałem z serwera.

Jak przekonwertować a Vec<u8>(lub a &[u8]) na a String?

Athabaska Dick
źródło

Odpowiedzi:

104

Aby przekonwertować wycinek bajtów na kawałek ciągu (zakładając kodowanie 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);
}

Konwersja odbywa się na miejscu i nie wymaga alokacji. Jeśli to konieczne, możesz utworzyć Stringkawałek struny, wywołując .to_owned()ten kawałek ( dostępne są inne opcje ).

Odniesienie do biblioteki dla funkcji konwersji:

gavinb
źródło
Możesz dodać, że jest to możliwe, ponieważ Vec przymusza do plasterków
torkleyy
chociaż przykładowy kod w rzeczywistości nie używa wektora :-)
Andrew Mackenzie
Chociaż prawdą jest, że from_utf8nie alokuje, warto wspomnieć, że musi skanować dane, aby sprawdzić poprawność utf-8. Więc to nie jest operacja O (1) (o czym można by pomyśleć na początku)
Zargony
69

Wolę String::from_utf8_lossy:

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

Zamienia nieprawidłowe bajty UTF-8 na , więc nie jest wymagana obsługa błędów. Jest dobry, gdy tego nie potrzebujesz, a ja prawie tego nie potrzebuję. Właściwie to dostajesz Stringz tego. Powinno to ułatwić drukowanie tego, co otrzymujesz z serwera.

Czasami może być konieczne użycie into_owned()metody, ponieważ jest ona klonowana podczas zapisu.

Bjorn
źródło
4
Wielkie dzięki za into_owned()sugestię! Dokładnie tego szukałem (to sprawia, że ​​stało się to właściwe, Stringktóre możesz na przykład zwrócić jako wartość zwracaną z metody).
Per Lundberg,
49

Jeśli faktycznie masz wektor bajtów ( Vec<u8>) i chcesz przekonwertować go na a String, najbardziej wydajne jest ponowne użycie alokacji z 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
źródło
2
Dzięki! Dlaczego pozostałe dwie odpowiedzi zignorowały pytanie?
Jehan
1
@Jehan, ponieważ ludzie na ogół nie są dobrzy w zadawaniu pytań, zwłaszcza gdy są nowicjuszami w jakimś języku. Rust rozróżnia tablicę , wycinek i a Vec, ale nowicjusze nie znają różnic. Pamiętaj jednak, aby zagłosować za wszystkimi pytaniami i odpowiedziami, które okażą się przydatne.
Shepmaster
Zauważ, że jak wspomniał @Bjorn Tipling, możesz użyć String::from_utf8_lossyzamiast tego tutaj, wtedy nie potrzebujesz połączenia oczekującego.
James Ray
2
Edycja: Zauważ, że jak wspomniał @Bjorn Tipling, możesz pomyśleć, że możesz użyć String::from_utf8_lossyzamiast tego tutaj, wtedy nie potrzebujesz expectwywołania, ale wejście do tego jest kawałkiem bytess ( &'a [u8]). OTOH, jest też from_utf8_unchecked. „Jeżeli jesteś pewien, że kawałek jest ważny bajt UTF-8, a ty nie chcesz ponosić napowietrznej konwersji, jest niebezpieczna wersja tej funkcji [ from_utf8_lossy], from_utf8_unchecked, który ma ten sam problem, ale pomijają sprawdzenie. "
James Ray
Zauważ, że możesz użyć &vec_of_bytesdo konwersji z powrotem na wycinek bajtów, jak wymieniono w przykładach from_utf8_lossy. doc.rust-lang.org/std/string/…
James Ray