Strings

Links:

Статьи в разделе:

В Rust строки хранятся в формате UTF-8, где каждый символ может занимать от 1 до 4 байт. Поэтому индексация идёт не по символам напрямую, а по байтам или с учётом корректных границ символов (Unicode scalar values).

Пример строкового литерала:

let s = "Hello, Rust!"; // Обычная строка, строковый литерал
let raw = r#"Сырой текст с "кавычками""#; // Сырая строка без экранирования

String

Тип данных с владельцем. Имеет изменяемый размер, неизвестный в момент компиляции. Представляет собой векторную структуру:

pub struct String { vec: Vec<u8>; } // для ASCII символов

Поскольку структура содержит Vec, это значит, что есть указатель на массив памяти, размер строки size структуры и ёмкость capacity (сколько можно добавить к строке перед дополнительным выделением памяти под строку).

Работа с String: если у вас String, нужно сначала получить срез &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 её в области жизни нельзя менять содержимое памяти, на которое она ссылается, даже владельцем строки.

&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

Строковые константы

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() }

Структуры

Если структуре надо владеть своими данными - использовать 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, переменная всё ещё в области действия!
}

Разница между to_lowercase(), to_ascii_lowercase(), make_ascii_lowercase() и upper-аналогов

Функция to_uppercase() to_ascii_uppercase() make_ascii_uppercase()
Возвращает Новая String Новая String () (меняет входную строку)
Текст Unicode только ASCII только ASCII
Память Новая строка Новая строка Не выделяет память
Speed Медленно Быстро Быстрее всех
Особенности Обработка спец-символов (ß→SS) Нет, пропускает спец-символы Нет, пропускает спец-символы