Рядки
Два найуживаніші типи рядків у Rust — це String і &str.
String зберігається як вектор байтів (Vec<u8>), але гарантовано
завжди є дійсною послідовністю UTF-8. String розміщується в купі, може
збільшуватися і не завершується нульовим байтом.
&str — це зріз (&[u8]), який завжди вказує на дійсну послідовність UTF-8, і
може використовуватися для перегляду всередину String, так само як &[T] — це перегляд у Vec<T>.
fn main() {
// (усі анотації типів є зайвими)
// Посилання на рядок, розміщений у пам'яті лише для читання
let pangram: &'static str = "the quick brown fox jumps over the lazy dog";
println!("Pangram: {}", pangram);
// Ітеруйте слова у зворотному порядку, новий рядок не розміщується
println!("Words in reverse");
for word in pangram.split_whitespace().rev() {
println!("> {}", word);
}
// Скопіюйте символи у вектор, відсортуйте та видаліть дублікати
let mut chars: Vec<char> = pangram.chars().collect();
chars.sort();
chars.dedup();
// Створіть порожній і змінюваний `String`
let mut string = String::new();
for c in chars {
// Вставте `char` у кінець рядка
string.push(c);
// Вставте рядок у кінець рядка
string.push_str(", ");
}
// Обрізаний рядок є зрізом початкового рядка, отже жодного нового
// виділення не виконується
let chars_to_trim: &[char] = &[' ', ','];
let trimmed_str: &str = string.trim_matches(chars_to_trim);
println!("Used characters: {}", trimmed_str);
// Розмістіть рядок у купі
let alice = String::from("I like dogs");
// Виділіть нову пам'ять і збережіть там змінений рядок
let bob: String = alice.replace("dog", "cat");
println!("Alice says: {}", alice);
println!("Bob says: {}", bob);
}
Більше методів str/String можна знайти в
std::str і
std::string
модулях
Літерали та екранування
Існує кілька способів записувати рядкові літерали зі спеціальними символами.
Усі вони дають подібний &str, тож найкраще використовувати той формат, який
найзручніше писати. Аналогічно існує кілька способів записувати байтові рядкові літерали,
які всі дають &[u8; N].
Зазвичай спеціальні символи екрануються символом зворотної скісної риски: \.
Так ви можете додати до свого рядка будь-який символ, навіть той, що не друкується,
і той, який ви не знаєте, як ввести. Якщо вам потрібна буквальна зворотна скісна риска,
екрануйте її ще однією: \\
Роздільники рядкового або символьного літерала, що зустрічаються всередині літерала, потрібно екранувати: "\"", '\''.
fn main() {
// Ви можете використовувати екранування, щоб записувати байти за їхніми шістнадцятковими значеннями...
let byte_escape = "I'm writing \x52\x75\x73\x74!";
println!("Що ви робите\x3F (\\x3F означає ?) {}", byte_escape);
// ...або кодові точки Unicode.
let unicode_codepoint = "\u{211D}";
let character_name = "\"DOUBLE-STRUCK CAPITAL R\"";
println!("Символ Unicode {} (U+211D) називається {}",
unicode_codepoint, character_name );
let long_string = "String literals
can span multiple lines.
The linebreak and indentation here ->\
<- can be escaped too!";
println!("{}", long_string);
}
Іноді є просто надто багато символів, які потрібно екранувати, або ж просто набагато зручніше записати рядок як є. Саме тут у гру вступають сирі рядкові літерали.
fn main() {
let raw_str = r"Escapes don't work here: \x3F \u{211D}";
println!("{}", raw_str);
// Якщо вам потрібні лапки в сирому рядку, додайте пару #s
let quotes = r#"And then I said: "There is no escape!""#;
println!("{}", quotes);
// Якщо вам потрібно "# у вашому рядку, просто використайте більше #s у роздільнику.
// Ви можете використовувати до 255 #s.
let longer_delimiter = r###"A string with "# in it. And even "##!"###;
println!("{}", longer_delimiter);
}
Потрібен рядок, який не є UTF-8? (Пам’ятайте, str і String мають бути дійсним UTF-8).
Або, можливо, ви хочете масив байтів, який здебільшого є текстом? На допомогу приходять байтові рядки!
use std::str;
fn main() {
// Зверніть увагу, що це насправді не `&str`
let bytestring: &[u8; 21] = b"this is a byte string";
// Байтові масиви не мають трейту `Display`, тож друк їх трохи обмежений
println!("A byte string: {:?}", bytestring);
// Байтові рядки можуть мати екранування байтів...
let escaped = b"\x52\x75\x73\x74 as bytes";
// ...але не можуть мати екранування Unicode
// let escaped = b"\u{211D} is not allowed";
println!("Some escaped bytes: {:?}", escaped);
// Сирі байтові рядки працюють так само, як і сирі рядки
let raw_bytestring = br"\u{211D} is not escaped here";
println!("{:?}", raw_bytestring);
// Перетворення байтового масиву на `str` може завершитися невдачею
if let Ok(my_str) = str::from_utf8(raw_bytestring) {
println!("And the same as text: '{}'", my_str);
}
let _quotes = br#"You can also use "fancier" formatting, \
like with normal raw strings"#;
// Байтові рядки не зобов'язані бути UTF-8
let shift_jis = b"\x82\xe6\x82\xa8\x82\xb1\x82\xbb"; // "ようこそ" in SHIFT-JIS
// Але тоді їх не завжди можна перетворити на `str`
match str::from_utf8(shift_jis) {
Ok(my_str) => println!("Conversion successful: '{}'", my_str),
Err(e) => println!("Conversion failed: {:?}", e),
};
}
Для перетворень між кодуваннями символів перегляньте крейт encoding.
Докладніший перелік способів запису рядкових літералів і символів екранування наведено в розділі ‘Tokens’ Rust Reference.