Как преобразовать вектор байтов (Vec<u8>) в строку в Rust?
Основной способ: String::from_utf8()
Самый правильный и безопасный способ преобразовать Vec<u8> в строку — использовать функцию String::from_utf8(). Она проверяет, что все байты являются валидной последовательностью UTF-8, и возвращает Result<String, FromUtf8Error>. Это важно, потому что в Rust строки всегда должны быть корректным UTF-8.
fn main() {
let bytes: Vec<u8> = vec![72, 101, 108, 108, 111]; // "Hello"
match String::from_utf8(bytes) {
Ok(text) => println!("Успех: {}", text),
Err(e) => println!("Ошибка UTF-8: {}", e),
}
}
Когда вы уверены в данных: String::from_utf8_unchecked()
Если вы абсолютно уверены, что байты представляют валидный UTF-8 (например, вы сами их создали из правильной строки), можно использовать unsafe функцию String::from_utf8_unchecked(). Она не выполняет проверку и работает быстрее, но использовать её нужно с осторожностью:
fn main() {
let bytes: Vec<u8> = vec![72, 101, 108, 108, 111];
let text = unsafe { String::from_utf8_unchecked(bytes) };
println!("{}", text);
}
Если нужно проигнорировать ошибки UTF-8
Иногда данные могут содержать невалидные байты. В таких случаях можно использовать String::from_utf8_lossy(). Она заменяет некорректные последовательности на символ замены � (U+FFFD) и возвращает Cow<'_, str>:
fn main() {
let bad_bytes: Vec<u8> = vec![0x48, 0x65, 0x6C, 0xC3, 0xA9, 0xFF]; // "Hellé" + невалидный байт
let text = String::from_utf8_lossy(&bad_bytes);
println!("{}", text); // Выведет: "Hellé�"
}
Преобразование из &[u8] в &str
Если у вас срез байтов &[u8], а не владеющий вектор, используйте std::str::from_utf8():
fn main() {
let bytes: &[u8] = &[72, 101, 108, 108, 111];
match std::str::from_utf8(bytes) {
Ok(text) => println!("{}", text),
Err(_) => println!("Невалидный UTF-8"),
}
}
Рекомендации
- Всегда используйте
from_utf8(), если не уверены в источнике данных. Это защитит вашу программу от паник и неопределённого поведения. - Избегайте
from_utf8_unchecked()без крайней необходимости. Даже если вы уверены сегодня, завтра данные могут измениться. - Для пользовательского ввода или файлов лучше всего подходит
from_utf8_lossy()— он никогда не паникует и даёт разумный результат. - Помните, что
Vec<u8>после успешного преобразованияfrom_utf8()становится недоступным, так как его владение переходит вString. Если нужно сохранить исходные байты, передавайте ссылку&bytes.
Альтернативный подход: использование крейта encoding
Если вы работаете с текстом в кодировках, отличных от UTF-8 (например, Windows-1251, UTF-16 или Latin-1), стандартные средства Rust не помогут. В этом случае используйте крейт encoding или encoding_rs.
// Добавьте в Cargo.toml: encoding = "0.2"
use encoding::{Encoding, DecoderTrap};
use encoding::all::WINDOWS_1251;
fn main() {
let bytes: Vec<u8> = vec![0xCF, 0xF0, 0xE8, 0xE2, 0xE5, 0xF2]; // "Привет" в Windows-1251
let text = WINDOWS_1251.decode(&bytes, DecoderTrap::Strict).unwrap();
println!("{}", text);
}
Когда это полезно
- Чтение старых текстовых файлов в не-UTF кодировках.
- Обработка данных из устаревших протоколов или баз данных.
- Интернационализация, когда нужно поддерживать разные языки без потери символов.
Крейт encoding_rs считается более современным и быстрым, но имеет схожий API. Выбирайте в зависимости от ваших потребностей.