Перейти к содержанию

Строки в Rust

Posted on:30 марта 2023 г. at 10:07

Example Dynamic OG Image link Да, вы все правильно расслышали. Эта часть будет посвящена строкам. Вы можете подумать, что уже знаете все, что нужно знать о строках, но в Rust есть некоторые особенности поведения, о которых вам следует знать.

Что такое строка? Проще говоря, строка - это вектор байтов. Это означает, что строка может увеличиваться или уменьшаться в размерах подобно вектору. В Rust есть два представления строк, строка (String) и срез строки (&str). Первый - это фактический вектор байтов, представленный в виде текста в кодировке UTF-8. Второй вариант, называемый string slice, обладает меньшими возможностями, чем первый. Оба этих представления хранят строки в кодировке UTF-8.

Шпаргалка строкового типа

// Создает пустую строку
let mut s = String::new();
// Создание среза строки (&str)
let data = "initial contents";
// Преобразовать &str в новое String значение
let s = data.to_string();
// метод также работает непосредственно с литералом:
let s = "initial contents".to_string();
// Создание строки с содержимым
let s = String::from("initial contents");
// Строки имеют полную поддержку UTF-8
// Это позволяет использовать любой язык или символ, поддерживаемый UTF-8
let hello = String::from("السلام عليكم");
let hello = String::from("Dobrý den");
let hello = String::from("Hello");
let hello = String::from("שָׁלוֹם");
let hello = String::from("नमस्ते");
let hello = String::from("こんにちは");
let hello = String::from("안녕하세요");
let hello = String::from("你好");
let hello = String::from("Olá");
let hello = String::from("Здравствуйте");
let hello = String::from("Hola");
// Мы можем добавить к строке push_str
let mut s = String::from("foo");
s.push_str("bar");
// Мы можем добавить один символ с помощью push
let mut s = String::from("lo");
s.push('l');
// Мы можем объединить несколько строк вместе макросом format!
let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");
let s = format!("{s1}-{s2}-{s3}");
// Для добавления двух строк можно использовать оператор +
// Но это возьмет в собственность первый аргумент
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2; // Примечание: s1 было перемещено сюда и больше не может использоваться
// Мы можем взять срез(&str) из нашей строки
// Но поскольку каждый символ этого алфавита занимает два байта
// Это вернет «Зд»
let hello = "Здравствуйте";
let s = &hello[0..4];
// Мы можем взять срез(&str) из нашей строки
// Но поскольку каждый символ этого алфавита занимает два байта
// Это вернет «Зд»
let hello = "Здравствуйте";
let s = &hello[0..4];
// Мы можем использовать .chars для получения вектора символов
// Мы можем получить первые 4 символа и создать новую строку
// Это вернет «Здра»
let mut chars = "Здравствуйте".chars();
let mut short = String::new();
for _ in 0..4 {
    short.push(chars.next().unwrap());
}
println!("{}", short);

Упражнения:

Исправляем ошибки.

strings1.rs

fn main() {
    let answer = current_favorite_color();
    println!("Мой текущий любимый цвет - {}", answer);
}

fn current_favorite_color() -> String {
    "синий"
}

Функция возвращает “синий”, который представляет собой срез строки. Используя встроенный метод to_string. Мы можем преобразовать это в строку и решить нашу проблему.

fn main() {
    let answer = current_favorite_color();
    println!("Мой текущий любимый цвет - {}", answer);
}

fn current_favorite_color() -> String {
    "синий".to_string()
}

strings2.rs

fn main() {
    let word = String::from("зеленый"); // Постарайтесь не изменять эту строку :)
    if is_a_color_word(word) {
        println!("Это слово представляет цвет, которое я знаю!");
    } else {
        println!("Это слово представляет цвет, который я не знаю.");
    }
}

fn is_a_color_word(attempt: &str) -> bool {
    attempt == "зеленый"  attempt == "синий"  attempt == "красный"
}

Теперь мы видим тот же сценарий с другой стороны. Мы можем передать word в качестве ссылки &word, и никаких других изменений не требуется.

fn main() {
    let word = String::from("зеленый"); // Постарайтесь не изменять эту строку :)
    if is_a_color_word(&word) {
        println!("Это слово представляет цвет, которое я знаю!");
    } else {
        println!("Это слово представляет цвет, который я не знаю.");
    }
}

fn is_a_color_word(attempt: &str) -> bool {
    attempt == "зеленый"  attempt == "синий"  attempt == "красный"
}

strings3.rs

fn trim_me(input: &str) -> String {
    // TODO: Удалите пробел с обоих концов строки!
    ???
}

fn compose_me(input: &str) -> String {
    // TODO: Добавьте «мир!» в строку! Есть несколько способов сделать это!
    ???
}

fn replace_me(input: &str) -> String {
    // TODO: Заменить «машины» в строке на «воздушные шары»!
    ???
}

В этом упражнении мы будем использовать trim, format! и replace для решения каждой из этих проблем. trim удалит все пробелы до и в конце нашей строки. format! объединит две строки вместе, чтобы создать новую. replace заменит первый строковый аргумент вторым.

fn trim_me(input: &str) -> String {
    input.trim().to_string()
}

fn compose_me(input: &str) -> String {
    format!("{} мир!", input)
}

fn replace_me(input: &str) -> String {
    input.replace("машины", "воздушные шары")
}

strings4.rs

fn string_slice(arg: &str) {
    println!("{}", arg);
}
fn string(arg: String) {
    println!("{}", arg);
}

fn main() {
    ???("синий");
    ???("красный".to_string());
    ???(String::from("привет"));
    ???("rust это весело!".to_owned());
    ???("хорошая погода".into());
    ???(format!("Интерполяция {}", "Станция"));
    ???(&String::from("abc")[0..1]);
    ???("  привет вам ".trim());
    ???("С понедельником!".to_string().replace("понедельником", "вторником"));
    ???("mY sHiFt KeY iS sTiCkY".to_lowercase());
}

Хорошо, вот несколько значений — некоторые из них String, некоторые &str. Ваша задача состоит в том, чтобы вызвать одну из этих двух функций для каждого значения в зависимости от того, что, по вашему мнению, представляет собой каждое значение. То есть добавьте либо string_slice, либо string перед круглыми скобками в каждой строке. Если вы правы, он будет скомпилирован.

Я оставляю это последнее упражнение на ваше усмотрение. Для вас будет лучше повозиться и совершать ошибки, чтобы понять разницу, чем для меня дать вам ответ здесь. Удачи!