String Methods

Вывод строк

  • Макрос println! позволяет вывести строку в поток stdout;
// println!("Hello there!\n"); 
// раскрывается в такой код:
use std::io::{self, Write};
io::stdout().lock().write_all(b"Hello there!\n").unwrap();
  • Макрос dbg!() позволяет вывести переменные и структуры в поток stdout;

split()

Метод split: разбивает строку на части по указанному разделителю и возвращает итератор. Разделитель может быть символом, строкой или даже пробелом. В том числе можно делить по нескольким символам разом:

let text = String::from("the_stealth-warrior");
let parts = text.split(['-', '_']).collect::<Vec<&str>>();
// collect собирает в коллекцию типа вектор
for part in parts {
    println!("{}", part);

Другие методы разбивки

split_whitespace()

Разбивает по любым пробельным символам (пробелы, табы, переносы строк).

let text = "apple   banana\ncherry";
let words: Vec<&str> = text.split_whitespace().collect();
println!("{:?}", words); // ["apple", "banana", "cherry"]

splitn(n, delimiter)

Разбивает только на первые n частей:

let text = "a,b,c,d";
let parts: Vec<&str> = text.splitn(3, ",").collect();
println!("{:?}", parts); // ["a", "b", "c,d"]

Склеивание строк (конкатенация)

В Rust надо учитывать, что String владеет памятью, а &str — нет.

Оператор +

String + &str работает, но забирает владение у первой строки.

let s1 = String::from("hello");
let s2 = " world";
let res = s1 + s2; // res == "hello world", s1 больше нельзя использовать

push_str()

Метод push_str() добавляет &str к существующей String, не забирая владение (строка должна быть mut).

let mut s = String::from("hello");
s.push_str(" world"); // s == "hello world"

push()

Добавляет один символ:

let mut s = String::from("hello");
s.push('!'); // s == "hello!"

join()

Склеивает коллекцию (вектор) строк с разделителем:

let words = vec!["apple", "banana", "cherry"];
let res = words.join(", "); // res == "apple, banana, cherry"

format!()

Мощный способ объединять строки. Макрос format! позволяет сформировать строку и вернуть из функции;

fn output_string(t: &String) -> String {  
    format!("Hello, {}",t)   // возврат сформированной строки  
}

При этом format!() позволяет конвертировать формат чисел. Decimal -> HEX:

fn rgb(r: i32, g: i32, b: i32) -> String {
    format!(
        "{:02X}{:02X}{:02X}", // конвертация dec -> 2 символа UPPER hex
        // {:02x} => конвертация в lower hex. 
        r.clamp(0, 255), // clamp задаёт валидный диапазон чисел
        g.clamp(0, 255), // аналог == g.min(255).max(0)
        b.clamp(0, 255))}

fn main() {
    println!("{}", rgb(1, 2, 3)); // 010203
    println!("{}", rgb(255, 255, 255)); // FFFFFF
    println!("{}", rgb(-20, 275, 125)); // 00FF7D
}

Decimal -> Binary:

let b = format!("{:b}", 42);
println!("{}", b); // 101010

Другие популярные методы работы со строками

  • Метод len() выдаёт длину строки в байтах;
  • Метод is_empty() проверят, что строка непустая;
  • Метод contains() ищет одну строку в другой строке;
  • Метод replace(from,to) заменяет часть строки на другую и выдаёт результат;
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")); 
}   

Пример задачи

Нахождение закономерностей в структурах со строками

В примере мы передаём вектор из строк. Далее, анализируем его по частям:

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