Как преобразовать вектор байтов (u8) в строку

100

Я пытаюсь написать простой клиент TCP / IP в Rust, и мне нужно распечатать буфер, который я получил с сервера.

Как мне преобразовать Vec<u8>(или &[u8]) в String?

Атабаска Дик
источник

Ответы:

105

Чтобы преобразовать отрезок байтов в отрезок строки (при условии кодировки 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);
}

Преобразование выполняется на месте и не требует выделения. При необходимости вы можете создать Stringиз фрагмента строки, вызвав .to_owned()этот фрагмент ( доступны другие параметры ).

Ссылка на библиотеку для функции преобразования:

Гавинб
источник
Вы можете добавить, что это возможно, потому что Vec принуждает к срезам
torkleyy
хотя в примере кода на самом деле вектор не используется :-)
Эндрю Маккензи
Хотя это правда, что from_utf8не выделяется, возможно, стоит упомянуть, что для проверки правильности utf-8 необходимо сканировать данные. Так что это не операция O (1) (о которой сначала можно подумать)
Заргони
70

Я предпочитаю String::from_utf8_lossy:

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

Он превращает недопустимые байты UTF-8 в , поэтому обработка ошибок не требуется. Это хорошо, когда тебе это не нужно, а мне это вряд ли нужно. Вы действительно получаете Stringот этого. Это должно упростить распечатку того, что вы получаете с сервера.

Иногда вам может потребоваться использовать этот into_owned()метод, поскольку он клонируется при записи.

Bjorn
источник
4
Большое спасибо за into_owned()предложение! Это именно то, что я искал (это делает его подходящим, Stringкоторый вы можете возвращать как возвращаемое значение из метода, например).
Пер Лундберг
50

Если у вас действительно есть вектор bytes ( Vec<u8>) и вы хотите преобразовать его в a String, наиболее эффективным будет повторное использование выделения с помощью String::from_utf8:

fn main() {
    let bytes = vec![0x41, 0x42, 0x43];
    let s = String::from_utf8(bytes).expect("Found invalid UTF-8");
    println!("{}", s);
}
Шепмастер
источник
2
Благодарность! Почему два других ответа игнорировали вопрос?
Jehan
1
@Jehan, потому что люди обычно не умеют задавать вопросы, особенно когда они плохо знакомы с языком. Rust делает различие между массивом , срезом и a Vec, но новички не знают различий. Не забудьте проголосовать за все вопросы и ответы, которые окажутся полезными.
Shepmaster
Обратите внимание, что, как упомянул @Bjorn Tipling, вы можете использовать String::from_utf8_lossyвместо этого здесь, тогда вам не нужен ожидаемый вызов.
Джеймс Рэй
2
Изменить: обратите внимание, что, как упоминалось @Bjorn Tipling, вы можете подумать, что можете использовать String::from_utf8_lossyвместо этого здесь, тогда вам не нужен expectвызов, но вход в него - это фрагмент bytess ( &'a [u8]). OTOH, тоже есть from_utf8_unchecked. «Если вы уверены , что срез байт действителен UTF-8, и вы не хотите брать на себя накладные расходы на преобразование, есть небезопасная версия этой функции [ from_utf8_lossy], from_utf8_unchecked, которая имеет такое же поведение , но пропускает проверку. "
Джеймс Рэй
Обратите внимание, что вы можете использовать &vec_of_bytesдля обратного преобразования в фрагмент байтов, как указано в примерах from_utf8_lossy. doc.rust-lang.org/std/string/…
Джеймс Рэй