Как преобразовать Vec<char> в String в Rust?
Основной способ: использование итератора и collect()
Самый простой и идиоматичный способ преобразовать Vec<char> в String — это использовать метод iter() и collect():
let chars: Vec<char> = vec!['H', 'e', 'l', 'l', 'o'];
let s: String = chars.iter().collect();
println!("{}", s); // "Hello"
Здесь iter() возвращает итератор по ссылкам на элементы вектора (&char), а collect() собирает их в строку, потому что String реализует трейт FromIterator для элементов &char.
Альтернатива: потребление вектора
Если вам больше не нужен исходный вектор, можно использовать into_iter(), который потребляет вектор и передаёт владение элементами:
let chars: Vec<char> = vec!['H', 'e', 'l', 'l', 'o'];
let s: String = chars.into_iter().collect();
// chars теперь недоступен
println!("{}", s); // "Hello"
Этот вариант может быть чуть эффективнее, так как избегает копирования символов, но делает вектор недоступным после преобразования.
Использование String::extend()
Можно также создать пустую строку и добавить в неё символы через extend():
let chars: Vec<char> = vec!['H', 'e', 'l', 'l', 'o'];
let mut s = String::new();
s.extend(chars.iter());
println!("{}", s); // "Hello"
Этот способ полезен, если вы хотите добавить символы в уже существующую строку.
Что делать, если у вас Vec<&char>?
Если у вас вектор ссылок на символы, ситуация аналогична:
let chars: Vec<&char> = vec![&'H', &'e', &'l', &'l', &'o'];
let s: String = chars.into_iter().collect();
println!("{}", s); // "Hello"
Почему не работает to_string() или String::from()?
В Rust трейт ToString реализован для типов, которые реализуют Display. Vec<char> не реализует Display, поэтому to_string() не сработает. String::from() ожидает тип, который реализует From<T>, но Vec<char> не реализует From<Vec<char>> для String. Поэтому итераторный подход — правильный путь.
Производительность
Все эти способы имеют сложность O(n) и примерно одинаковую производительность. Если вам нужно максимальное быстродействие, можно использовать unsafe код с String::from_raw_parts(), но это крайне не рекомендуется для новичков и обычно не нужно.
Резюме
- Используйте
chars.iter().collect()— самый безопасный и читаемый способ. - Если вектор больше не нужен —
chars.into_iter().collect(). - Избегайте ручного управления памятью, пока не освоите основы.
Дополнительный способ: использование String::from_iter()
Можно также явно вызвать String::from_iter(), что эквивалентно collect(), но более явно:
let chars: Vec<char> = vec!['H', 'e', 'l', 'l', 'o'];
let s = String::from_iter(chars.iter());
println!("{}", s); // "Hello"
Обработка ошибок: невалидные символы
Важно помнить, что char в Rust — это Unicode-символы, и все они валидны для String. Поэтому преобразование всегда успешно. Но если у вас Vec<u8> (байты), то нужно использовать String::from_utf8() с обработкой ошибок:
let bytes: Vec<u8> = vec![72, 101, 108, 108, 111]; // "Hello" в UTF-8
let s = String::from_utf8(bytes).expect("Invalid UTF-8");
println!("{}", s); // "Hello"
Если нужно удалить дубликаты или отфильтровать
Можно комбинировать с другими итераторными методами:
let chars: Vec<char> = vec!['H', 'e', 'l', 'l', 'o'];
let s: String = chars.iter()
.filter(|&c| c != 'l') // удаляем все 'l'
.collect();
println!("{}", s); // "Heo"
Этот подход даёт гибкость и сохраняет идиоматичность Rust-кода.