Strings
Статья по ссылкам на память в Rust
Статьи в разделе:
- Chars
Character Methods
- String Iterators
String Iterator Methods
String
Тип данных с владельцем. Имеет изменяемый размер, неизвестный в момент компиляции. Представляет собой векторную структуру:
pub struct String { vec: Vec<u8>; }Поскольку структура содержит Vec, это значит, что есть указатель на массив памяти, размер строки size структуры и ёмкость capacity (сколько можно добавить к строке перед дополнительным выделением памяти под строку).
&String
Ссылка на String. Не имеет владельца, размер фиксирован, известен в момент компиляции.
fn change(mystring: &mut String) {
if !mystring.ends_with("s") {
mystring.push_str("s"); // добавляем "s" в конец исходной строки
}str
Набор символов (литералов), размещённых на стеке. Не имеет владельца, размер фиксирован, известен в момент компиляции. Можно превращать str в String через признак from:
let text = String::from("TEST"); // "TEST" :str
&str
Ссылка на часть, slice от String (куча), str (стек) или статической константы. Не имеет владельца, размер фиксирован, известен в момент компиляции.
- &String можно неявно превращать в &str;
- &str нельзя неявно превращать в &String.
fn main() {
let s = "hello_world";
let mut mut_string = String::from("hello");
success(&mutable_string);
fail(s); }
fn success(data: &str) { // неявный перевод &String -> &str
println!("{}", data); }
fn fail(data: &String) { // ОШИБКА - expected &String, but found &str
println!("{}", data); }Warning
Пока существует &str её в области жизни нельзя менять содержимое памяти, на которое она ссылается, даже владельцем строки.
Строковые константы
const CONST_STRING: &'static str = "a constant string";
Примеры
Изменение строк
При наличии String, нужно передать ссылку &mut String для изменения:
fn main() {
let mut mutable_string = String::from("hello ");
do_mutation(&mut mutable_string);
println!("{}", mutables_string); // hello world!
}
fn do_mutation(input: &mut String) {
input.push_str("world!");
}Строки с владением
Получение String с передачей владения нужно при получении строки от функции, передача в поток (thread):
fn main() {
let s = "hello_world";
println!("{}", do_upper(s)); } // HELLO_WORLD
fn do_upper(input: &str) -> String { // возврат String
input.to_ascii_uppercase() }Вывод строк
- Макрос
println!позволяет вывести строку в поток stdout;
// println!("Hello there!\n");
// раскрывается в такой код:
use std::io::{self, Write};
io::stdout().lock().write_all(b"Hello there!\n").unwrap();- Макрос
format!позволяет сформировать строку и вернуть из функции; - Метод
len()выдаёт длину строки; - Метод
is_empty()проверят, что строка непустая; - Метод
contains()ищет одну строку в другой строке; - Метод
replace(from,to)заменяет часть строки на другую и выдаёт результат; - Метод
splt_whitespace()позволяет делить строку на части по пробелам; - Метод
push_str()позволяет добавить текст к строке (строка должна быть mut).
fn main() {
let mut a = String::from("Wonderful RUST World");
println!("Hello{}!", output_string(&a)); // вывод строки
println!("String is empty? {}", a.is_empty());
println!("String length: {}", a.len());
println!("Does string contain 'Hello'? {}", a.contains("Hello"));
println!("{}",a.replace("RUST","Python")); // Wonderful Python World
for i in a.split_whitespace() {
println!("{}", i);
}
a.push_str(" And let's go!");
println!("{}",a);
}
fn output_string(t: &String) -> String {
format!(", {}",t) // возврат сформированной строки
}Структуры
Если структуре надо владеть своими данными - использовать String. Если нет, можно использовать &str, но нужно указать время жизни (lifetime), чтобы структура не пережила взятую ей строку:
struct Owned { bla: String, }
struct Borrowed<'a> { bla: &'a str, }
fn main() {
let o = Owned {
bla: String::from("bla"), };
let b = create_something(&o.bla); }
fn create_something(other_bla: &str) -> Borrowed {
let b = Borrowed { bla: other_bla };
b // при возврате Borrowed, переменная всё ещё в области действия!
}Разделение строки на подстроки
Можно делить с помощью метода split(). В том числе можно делить по нескольким символам разом:
let text = String::from("the_stealth-warrior");
let parts = text2.split(['-', '_']);
for part in parts {
println!("{}", part);Задачи со строками
Нахождение закономерностей в структурах со строками
В примере мы передаём вектор из строк. Далее, анализируем его по частям:
fn likes(names: &[&str]) -> String {
match names {
[] => "no one likes this".to_string(),
[a] => format!("{} likes this", a),
[a, b] => format!("{} and {} like this", a, b),
[a, b, c] => format!("{}, {} and {} like this", a, b, c),
[a, b, other @ ..] => format!("{}, {} and {} others like this", a, b, other.len()),
}
}Разница между to_lowercase(), to_ascii_lowercase(), make_ascii_lowercase() и upper-аналогов
| Функция | to_uppercase() |
to_ascii_uppercase() |
make_ascii_uppercase() |
|---|---|---|---|
| Возвращает | Новая String |
Новая String |
() (меняет входную строку) |
| Текст | Unicode | только ASCII | только ASCII |
| Память | Новая строка | Новая строка | Не выделяет память |
| Speed | Медленно | Быстро | Быстрее всех |
| Особенности | Обработка спец-символов (ß→SS) | Нет, пропускает спец-символы | Нет, пропускает спец-символы |
