Как правильно создать структуру в Rust с полями типа String?
Используйте String для владения строкой
Вы на верном пути: основная проблема в том, что &str — это ссылка на данные, которыми кто-то другой владеет. Для структуры, которая должна полностью владеть своими строками (например, данные из пользовательского ввода, файла или просто строки, которые будут жить столько же, сколько сама структура), правильный выбор — String.
Вот исправленный пример:
struct Person {
name: String,
age: u32,
}
fn main() {
// Способ 1: преобразовать литерал в String
let person1 = Person {
name: "Alice".to_string(),
age: 30,
};
// Способ 2: использовать String::from()
let person2 = Person {
name: String::from("Bob"),
age: 25,
};
// Способ 3: использовать into() (работает благодаря From/Into)
let person3 = Person {
name: "Charlie".into(),
age: 35,
};
println!("{} is {} years old", person1.name, person1.age);
println!("{} is {} years old", person2.name, person2.age);
println!("{} is {} years old", person3.name, person3.age);
}
Почему это работает?
String— это владеющий тип: он хранит строку в куче и отвечает за её освобождение. Когда вы перемещаетеStringв структуру, структура становится новым владельцем.- Преобразование литерала:
"Alice"— это&str, но методы.to_string(),String::from()и.into()создают новый экземплярString, копируя данные из литерала. - Никаких времён жизни: структура
Personтеперь не содержит ссылок, поэтому компилятору не нужно проверять времена жизни. Код становится проще и безопаснее.
Когда можно использовать &str?
Если вы уверены, что структура не будет владеть строкой, а только ссылаться на неё (например, при парсинге большого текста), можно использовать &'a str с указанием времени жизни:
struct Person<'a> {
name: &'a str,
age: u32,
}
fn main() {
let name = "Alice".to_string();
let person = Person {
name: &name, // ссылка на существующую строку
age: 30,
};
println!("{}", person.name);
}
Но такой подход усложняет код и ограничивает использование структуры. Для большинства задач новичкам рекомендуется использовать String.
Лучшие практики
- Для полей, которые должны жить вместе со структурой — используйте
String. - Для временных ссылок или заимствованных данных —
&strс временем жизни. - Если не уверены — начинайте с
String. Вы всегда сможете оптимизировать позже.
Также обратите внимание: String можно легко преобразовать обратно в &str с помощью &s или s.as_str(), поэтому гибкость не теряется.
Альтернатива: использовать Box<str> для экономии памяти
Если вы хотите, чтобы структура владела строкой, но не планируете изменять её размер после создания, можно использовать Box<str>. Это занимает меньше памяти, чем String (на 8 байт меньше на 64-битной системе), потому что не хранит лишнюю ёмкость.
struct Person {
name: Box<str>,
age: u32,
}
fn main() {
let person = Person {
name: "Alice".to_string().into_boxed_str(),
age: 30,
};
// Или короче:
let person2 = Person {
name: "Bob".into(), // &str -> Box<str> через Into
age: 25,
};
println!("{}", person.name);
}
Минусы:
- Нельзя изменять строку после создания (нет методов
push_str,clearи т.д.). - Преобразование из
Stringтребует явного вызова.into_boxed_str().
Этот подход оправдан, если у вас много структур с короткими неизменяемыми строками (например, имена в базе данных). Для 99% случаев String — лучший выбор.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги
Конкурентность и многопоточность в Kotlin: корутины, потоки и практические примеры
Generics в PHP: зачем нужны и как использовать