Да, вы все правильно расслышали. Эта часть будет посвящена строкам. Вы можете подумать, что уже знаете все, что нужно знать о строках, но в 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
перед круглыми скобками в каждой строке. Если вы правы, он будет скомпилирован.
Я оставляю это последнее упражнение на ваше усмотрение. Для вас будет лучше повозиться и совершать ошибки, чтобы понять разницу, чем для меня дать вам ответ здесь. Удачи!