标准库

基础

fn main() {
  by_moving();
  by_cloning();
  by_mutating();
}

fn by_moving() {
  let hello = "hello ".to_string();
  let world = "world!";

  // 将hello变量移动到一个新变量中
  let hello_world = hello + world;
  // hello变量不能再被使用
  println!("{}", hello_world); 
}

fn by_cloning() {
  let hello = "hello ".to_string();
  let world = "world!";

  // 创建 hello 的副本并将其移动到新变量中
  let hello_world = hello.clone() + world;
  // hello变量仍可被使用
  println!("{}", hello_world); 
}

fn by_mutating() {
  let mut hello = "hello ".to_string();
  let world = "world!";

  // hello变量被修改了
  hello.push_str(world);
  // hello 既可用又可修改
  println!("{}", hello); 
}

在所有的函数中,我们首先为一个长度可变的字符串分配内存。通过创建一个字符串切片(&str)并在其上调用 to_string 函数来实现这一点。

在Rust中连接字符串的一种方法,如by_moving函数所示,是将上述分配的内存,连同一个额外的字符串切片,移入一个新的变量。用+运算符连接,非常简单明了。但这种方法是有缺点的,hello在第12行之后就不能使用了,因为它被移动了。

by_cloning看起来与第一个函数几乎相同,但它将分配的字符串克隆到一个临时对象中,在进程中分配新的内存,然后将其移动,使原始的 hello 保持不变并且仍然可以访问。当然,这样做的代价是在运行时进行多余的内存分配。

by_mutating是解决我们问题的有状态方法。它在原来的地方执行所涉及的内存管理,这意味着性能应该与 by_moving 中的相同。最后,它使hello可变,为进一步的改变做好准备。这个函数看起来不那么优雅,因为它没有使用 + 运算符。这是有意为之,因为 Rust 试图推动您通过其设计来移动数据,以便在不改变现有变量的情况下创建新变量。

fn main() {
    let colour = "red";
    // '{}'会被参数替换。
    let favourite = format!("My favourite colour is {}", colour);
    println!("{}", favourite);

    // 可以添加多个参数
    let hello = "hello ";
    let world = "world!";
    let hello_world = format!("{}{}", hello, world);
    println!("{}", hello_world); 

    // format! 宏可以连接任何实现了'Display' trait的数据类型,例如数字
    let favourite_num = format!("My favourite number is {}", 42);
    println!("{}", favourite_num); // "My favourite number is 42

    // 如果要在字符串中多次包含某些参数,可以使用位置索引参数
    let duck_duck_goose = format!("{0}, {0}, {0}, {1}!", "duck", "goose");
    println!("{}", duck_duck_goose); // "duck, duck, duck, goose!"

    // 你还可以给参数命名
    let introduction = format!(
        "My name is {surname}, {forename} {surname}",
        surname = "Bond",
        forename = "James"
    );
    println!("{}", introduction) // "My name is Bond, James Bond"
}

集合

Vector

fn main() {
    // 创建一个vector 
    let fruits = vec!["apple", "tomato", "pear"];
    // 不能直接打印向量,但我们可以debug-print 
    println!("fruits: {:?}", fruits);

    // 创建一个空 vector 并填充它
    let mut fruits = Vec::new();
    fruits.push("apple");
    fruits.push("tomato");
    fruits.push("pear");
    println!("fruits: {:?}", fruits);

    // 删除最后一个元素
    let last = fruits.pop();
    if let Some(last) = last {
        println!("Removed {} from {:?}", last, fruits);
    }

    // 在指定索引处插入一个元素
    fruits.insert(1, "grape");
    println!("fruits after insertion: {:?}", fruits);

    // 交换两个元素
    fruits.swap(0, 1);
    println!("fruits after swap: {:?}", fruits);

    // 访问第一个和最后一个元素
    let first = fruits.first();
    if let Some(first) = first {
        println!("First fruit: {}", first);
    }
    let last = fruits.last();
    if let Some(last) = last {
        println!("Last fruit: {}", last);
    }

    // 访问任意元素
    let second = fruits.get(1);
    if let Some(second) = second {
        println!("Second fruit: {}", second);
    }
    // 访问任意元素,不需要检查返回值
    let second = fruits[1];
    println!("Second fruit: {}", second);

    // 用一个值初始化向量 
    // 这里,用五个零填充向量
    let bunch_of_zeroes = vec![0; 5];
    println!("bunch_of_zeroes: {:?}", bunch_of_zeroes);

    // 删除指定索引处的元素
    let mut nums = vec![1, 2, 3, 4];
    let second_num = nums.remove(1);
    println!("Removed {} from {:?}", second_num, nums);

    // 过滤 vector
    let mut names = vec!["Aaron", "Felicia", "Alex", "Daniel"];
    // 只保留以"A"开头的名字
    names.retain(|name| name.starts_with('A'));
    println!("Names starting with A: {:?}", names);

    // 检查vector是否包含元素
    println!("Does 'names' contain \"Alex\"? {}", names.contains(&"Alex"));

    // 删除连续的重复内容
    let mut nums = vec![1, 2, 2, 3, 4, 4, 4, 5];
    nums.dedup();
    println!("Deduped, pre-sorted nums: {:?}", nums);

    // 如果数据未排序,应小心使用
    let mut nums = vec![2, 1, 4, 2, 3, 5, 1, 2];
    nums.dedup();
    // 可能打印出来的不是你所期望的
    println!("Deduped, unsorted nums: {:?}", nums);

    // 进行排序
    nums.sort();
    println!("Manually sorted nums: {:?}", nums);
    nums.dedup();
    println!("Deduped, sorted nums: {:?}", nums);

    // 反转
    nums.reverse();
    println!("nums after being reversed: {:?}", nums);

    // 在一个区间上创建消费迭代器
    let mut alphabet = vec!['a', 'b', 'c'];
    print!("The first two letters of the alphabet are: ");
    for letter in alphabet.drain(..2) {
        print!("{} ", letter);
    }
    println!();
    // 被抽出的元素不再在vector中
    println!("alphabet after being drained: {:?}", alphabet);


    // 检查vector是否为空
    let mut fridge = vec!["Beer", "Leftovers", "Mayonaise"];
    println!("Is the fridge empty {}", fridge.is_empty());
    // 删除所有元素
    fridge.clear();
    println!("Is the fridge now empty? {}", fridge.is_empty());

    // 将一个vector分成两部分
    let mut colors = vec!["red", "green", "blue", "yellow"];
    println!("colors before splitting: {:?}", colors);
    let half = colors.len() / 2;
    let mut second_half = colors.split_off(half);
    println!("colors after splitting: {:?}", colors);
    println!("second_half: {:?}", second_half);

    // 将两个vector放到一起
    colors.append(&mut second_half);
    println!("colors after appending: {:?}", colors);
    // 这将清空第二个vector
    println!("second_half after appending: {:?}", second_half);

    // 拼接一个vector
    let mut stuff = vec!["1", "2", "3", "4", "5", "6"];
    println!("Original stuff: {:?}", stuff);
    let stuff_to_insert = vec!["a", "b", "c"];
    let removed_stuff: Vec<_> = stuff.splice(1..4, stuff_to_insert).collect();
    println!("Spliced stuff: {:?}", stuff);
    println!("Removed stuff: {:?}", removed_stuff);

    // 优化:初始化具有指定容量的vector
    let mut large_vec: Vec<i32> = Vec::with_capacity(1_000_000);
    println!("large_vec after creation:");
    println!("len:\t\t{}", large_vec.len());
    println!("capacity:\t{}", large_vec.capacity());

    // 尽可能地将vector缩小到接近其长度
    large_vec.shrink_to_fit();
    println!("large_vec after shrinking:");
    println!("len:\t\t{}", large_vec.len());
    println!("capacity:\t{}", large_vec.capacity());

    // 删除指定项,用最后一个替换它
    let mut nums = vec![1, 2, 3, 4];
    let second_num = nums.swap_remove(1);
    // 这会改变顺序,性能为O(1) 
    println!("Removed {} from {:?}", second_num, nums);
}

vector应该始终是首选集合。在内部,它被实现为一个存储在堆上的连续的内存块。

缩短vector时,额外的容量并没有消失。如果你有一个长度为10,000、容量为100,000的vector,并对其调用clear,你仍然会有100,000的预分配容量。当在有内存限制的系统上工作时,如微控制器,这可能成为一个问题。解决方案是定期对这些向量调shrink_to_fit。这将使容量尽可能地接近长度,但允许仍然留下一点预分配的空间。

另一种优化方法是调用swap_remove。通常,当从vector中移除一个元素时,后面的所有元素将向左移动,以保留连续的内存。当移除一个很大的vector中的第一个元素时,这是一个很耗时的工作。如果你不关心vector的顺序,则可以调用swap_remove而不是remove。它的工作原理是将要删除的元素与最后一个元素进行交换,并调整长度。这样就不会产生内存移动,仅交换内存是一个非常快的操作。

字符串

String 只是一种字符vector

fn main() {
    // 由于 String 是一种vector,你可以用相同的方式构造它
    let mut s = String::new();
    s.push('H');
    s.push('i');
    println!("s: {}", s);

    // 然而,String也可以从字符串切片 (&str) 构造
    // 接下来的两种方法是等价的
    let s = "Hello".to_string();
    println!("s: {}", s);
    let s = String::from("Hello");
    println!("s: {}", s);

    // Rust 中的字符串总是有效的 UTF-8
    let s = "汉语 한글 Þjóðhildur 😉 🍺".to_string();
    println!("s: {}", s);

    // 将字符串相互附加
    let mut s = "Hello ".to_string();
    s.push_str("World");

    // 遍历字符
    // 此处将"character"定义为 Unicode 标量值
    for ch in "Tubular".chars() {
        print!("{}.", ch);
    }
    println!();
    // 但是要小心,"character"可能并不总是你所期望的
    for ch in "y̆".chars() {
        // 这不会打印 y̆
        print!("{} ", ch);
    }
    println!();

    // 以各种方式拆分字符串

    // 将一个字符串切片分成两半
    let (first, second) = "HelloThere".split_at(5);
    println!("first: {}, second: {}", first, second);

    // 在单独的行上拆分
    let haiku = "\
        she watches\n\
        satisfied after love\n\
        he lies\n\
        looking up at nothing\n\
    ";
    for line in haiku.lines() {
        println!("\t{}.", line);
    }

    // 拆分子串
    for s in "Never;Give;Up".split(';') {
        println!("{}", s);
    }
    // 当分割字符串在开头或结尾时,将导致空字符串
    let s: Vec<_> = "::Hi::There::".split("::").collect();
    println!("{:?}", s);

    // 可以使用 split_termitor 消除末尾的空字符串
    let s: Vec<_> = "Mr. T.".split_terminator('.').collect();
    println!("{:?}", s);

    // char 有一些方法可以用来拆分
    for s in "I'm2fast4you".split(char::is_numeric) {
        println!("{}", s);
    }

    // 只拆分一定的次数
    for s in "It's not your fault, it's mine".splitn(3, char::is_whitespace) {
        println!("{}", s);
    }

    // 只获取与模式匹配的子字符串,这与拆分相反
    for c in "The Dark Knight rises".matches(char::is_uppercase) {
        println!("{}", c);
    }

    // 检查字符串是否以某某开头
    let saying = "The early bird gets the worm";
    let starts_with_the = saying.starts_with("The");
    println!("Does \"{}\" start with \"The\"?: {}", saying, starts_with_the);
    let starts_with_bird = saying.starts_with("bird");
    println!("Does \"{}\" start with \"bird\"?: {}", saying, starts_with_bird);

    // 检查字符串是否以某某结尾
    let ends_with_worm = saying.ends_with("worm");
    println!("Does \"{}\" end with \"worm\"?: {}", saying, ends_with_worm);

    // 检查字符串是否包含某些内容
    let contains_bird = saying.contains("bird");
    println!("Does \"{}\" contain \"bird\"?: {}", saying, contains_bird);


    // 删除空格

    // 在空白处拆分可能不会产生期望的结果
    let a_lot_of_whitespace = "    I   love spaaace     ";
    let s: Vec<_> = a_lot_of_whitespace.split(' ').collect();
    println!("{:?}", s);
    // 改用 split_whitespace
    let s: Vec<_> = a_lot_of_whitespace.split_whitespace().collect();
    println!("{:?}", s);

    // 删除前后空格
    let username = "   P3ngu1n\n".trim();
    println!("{}", username);
    // 仅删除前面空格
    let username = "   P3ngu1n\n".trim_left();
    println!("{}", username);
    // 仅删除尾部空格
    let username = "   P3ngu1n\n".trim_right();
    println!("{}", username);


    // 将字符串解析为另一种数据类型
    // 这需要指定泛型
    let num = "12".parse::<i32>();
    if let Ok(num) = num {
        println!("{} * {} = {}", num, num, num * num);
    }

    // 修改字符串

    // 替换所有出现的模式
    let s = "My dad is the best dad";
    let new_s = s.replace("dad", "mom");
    println!("new_s: {}", new_s);

    // 用小写替换所有字符
    let lowercase = s.to_lowercase();
    println!("lowercase: {}", lowercase);

    // 用大写替换所有字符
    let uppercase = s.to_uppercase();
    println!("uppercase: {}", uppercase);

    // 这些也适用于其他语言
    let greek = "ὈΔΥΣΣΕΎΣ";
    println!("lowercase greek: {}", greek.to_lowercase());

    // 重复一个字符串
    let hello = "Hello! ";
    println!("Three times hello: {}", hello.repeat(3));
}

迭代器访问集合

fn main() {
    let names = vec!["Joe", "Miranda", "Alice"];
    // 可以通过多种方式访问迭代器
    // 几乎所有集合都实现了 .iter()
    let mut iter = names.iter();
    // 字符串本身是不可迭代的,但它的字符可以
    let mut alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".chars();
    // Range也是(有限的)迭代器
    let nums = 0..10;
    // 甚至可以创建无限迭代器
    let all_nums = 0..;

    // 你可以对迭代器进行迭代
    // 这将消费迭代器
    for num in nums {
        print!("{} ", num);
    }
    // nums 不再可用
    println!();

    // 获取当前项的索引
    for (index, letter) in "abc".chars().enumerate() {
        println!("#{}. letter in the alphabet: {}", index + 1, letter);
    }

    // 通过迭代器,一步一步迭代
    if let Some(name) = iter.next() {
        println!("First name: {}", name);
    }
    if let Some(name) = iter.next() {
        println!("Second name: {}", name);
    }
    if let Some(name) = iter.next() {
        println!("Third name: {}", name);
    }
    if iter.next().is_none() {
        println!("No names left");
    }

    // 任意访问迭代器中的项
    let letter = alphabet.nth(3);
    if let Some(letter) = letter {
        println!("the fourth letter in the alphabet is: {}", letter);
    }
    // 这是通过消耗所有项直到指定位置
    let current_first = alphabet.nth(0);
    if let Some(current_first) = current_first {
        // 不会打印“A”
        println!(
            "The first item in the iterator is currently: {}",
            current_first
        );
    }

    // 访问最后一项;将消耗整个迭代器
    let last_letter = alphabet.last();
    if let Some(last_letter) = last_letter {
        println!("The last letter of the alphabet is: {}", last_letter);
    }

    // 将迭代器收集到集合中,这需要指定返回的集合类型
    // 下面两个是等价的:
    let nums: Vec<_> = (1..10).collect();
    println!("nums: {:?}", nums);
    let nums = (1..10).collect::<Vec<_>>();
    println!("nums: {:?}", nums);

    // 修改正在迭代的项

    // 只取前 n 项
    // 可以使无限迭代器有限
    let nums: Vec<_> = all_nums.take(5).collect();
    println!("The first five numbers are: {:?}", nums);

    // 跳过前n项
    let nums: Vec<_> = (0..11).skip(2).collect();
    println!("The last 8 letters in a range from zero to 10: {:?}", nums);

    // 使用take_while 和skip_while接受闭包
    let nums: Vec<_> = (0..).take_while(|x| x * x < 50).collect();
    println!(
        "All positive numbers that are less than 50 when squared: {:?}",
        nums
    );

    // 对于过滤已经排序的vector很有用
    let names = ["Alfred", "Andy", "Jose", "Luke"];
    let names: Vec<_> = names.iter().skip_while(|x| x.starts_with('A')).collect();
    println!("Names that don't start with 'A': {:?}", names);

    // 过滤迭代器
    let countries = [
        "U.S.A.", "Germany", "France", "Italy", "India", "Pakistan", "Burma"
    ];
    let countries_with_i: Vec<_> = countries
        .iter()
        .filter(|country| country.contains('i'))
        .collect();
    println!(
        "Countries containing the letter 'i': {:?}",
        countries_with_i
    );

    // 检查迭代器是否包含元素

    // 找到满足条件的第一个元素
    if let Some(country) = countries.iter().find(|country| country.starts_with('I')) {
        println!("First country starting with the letter 'I': {}", country);
    }

    // 不获取搜索的项,而是获取它的索引
    if let Some(pos) = countries
        .iter()
        .position(|country| country.starts_with('I'))
    {
        println!("It's index is: {}", pos);
    }

    // 检查是否至少有一项满足条件
    let are_any = countries.iter().any(|country| country.len() == 5);
    println!(
        "Is there at least one country that has exactly five letters? {}",
        are_any
    );

    // 检查所有项是否满足条件
    let are_all = countries.iter().all(|country| country.len() == 5);
    println!("Do all countries have exactly five letters? {}", are_all);

    // 数字项的有用操作
    let sum: i32 = (1..11).sum();
    let product: i32 = (1..11).product();
    println!(
        "When operating on the first ten positive numbers\n\
         their sum is {} and\n\
         their product is {}.",
        sum, product
    );

    let max = (1..11).max();
    let min = (1..11).min();
    if let Some(max) = max {
        println!("They have a highest number, and it is {}", max);
    }
    if let Some(min) = min {
        println!("They have a smallest number, and it is {}", min);
    }

    // 组合迭代器

    // 将迭代器与自身结合,使其无限
    // 当它走到尽头时,它又重新开始
    let some_numbers: Vec<_> = (1..4).cycle().take(10).collect();
    println!("some_numbers: {:?}", some_numbers);

    // 通过把两个迭代器放在另一个迭代器之后来合并它们
    let some_numbers: Vec<_> = (1..4).chain(10..14).collect();
    println!("some_numbers: {:?}", some_numbers);

    // 将两个迭代器压缩在一起,它们的第一个项分组到一起,第二项也在一起,以此类推
    let swiss_post_codes = [8957, 5000, 5034];
    let swiss_towns = ["Spreitenbach", "Aarau", "Suhr"];
    let zipped: Vec<_> = swiss_post_codes.iter().zip(swiss_towns.iter()).collect();
    println!("zipped: {:?}", zipped);

    // 因为 zip 是惰性的,所以你可以使用两个范围限制
    let zipped: Vec<_> = (b'A'..)
        .zip(1..)
        .take(10)
        .map(|(ch, num)| (ch as char, num))
        .collect();
    println!("zipped: {:?}", zipped);

    // 将函数应用于所有项

    // 更改项的类型
    let numbers_as_strings: Vec<_> = (1..11).map(|x| x.to_string()).collect();
    println!("numbers_as_strings: {:?}", numbers_as_strings);

    // 遍历所有项
    println!("First ten squares:");
    (1..11).for_each(|x| print!("{} ", x));
    println!();

    // 同时过滤和映射项
    let squares: Vec<_> = (1..50)
        .filter_map(|x| if x % 3 == 0 { Some(x * x) } else { None })
        .collect();
    println!(
        "Squares of all numbers under 50 that are divisible by 3: {:?}",
        squares
    );

    // 迭代器的真正优势来自于它们的组合

    // 检索整个字母表的小写和大写字母:
    let alphabet: Vec<_> = (b'A' .. b'z' + 1) // 从 u8 开始
        .map(|c| c as char)                   // 全部转换为字符
        .filter(|c| c.is_alphabetic())        // 仅过滤字母字符
        .collect();                           // 收集为 Vec<char>
    println!("alphabet: {:?}", alphabet);
}

iter()会创建一个借用元素项的迭代器。如果你想创建一个消耗元素项的迭代器,例如,通过移动它们来获得它们的所有权,你可以使用 into_iter()

HashMap

use std::collections::HashMap;

fn main() {
    // HashMap 可以将任何可散列类型映射到任何其他类型
    // 第一种类型称为"key",第二种称为"value"
    let mut tv_ratings = HashMap::new();
    // 这里,我们将 &str 映射到 i32
    tv_ratings.insert("The IT Crowd", 8);
    tv_ratings.insert("13 Reasons Why", 7);
    tv_ratings.insert("House of Cards", 9);
    tv_ratings.insert("Stranger Things", 8);
    tv_ratings.insert("Breaking Bad", 10);

    // 检查key是否存在
    let contains_tv_show = tv_ratings.contains_key("House of Cards");
    println!("Did we rate House of Cards? {}", contains_tv_show);
    let contains_tv_show = tv_ratings.contains_key("House");
    println!("Did we rate House? {}", contains_tv_show);

    // 访问value
    if let Some(rating) = tv_ratings.get("Breaking Bad") {
        println!("I rate Breaking Bad {} out of 10", rating);
    }

    // 给相同key插入不同的value,就会覆盖它
    let old_rating = tv_ratings.insert("13 Reasons Why", 9);
    if let Some(old_rating) = old_rating {
        println!("13 Reasons Why's old rating was {} out of 10", old_rating);
    }
    if let Some(rating) = tv_ratings.get("13 Reasons Why") {
        println!("But I changed my mind, it's now {} out of 10", rating);
    }

    // 删除一个key和它的value
    let removed_value = tv_ratings.remove("The IT Crowd");
    if let Some(removed_value) = removed_value {
        println!("The removed series had a rating of {}", removed_value);
    }

    // 迭代访问所有键和值
    println!("All ratings:");
    for (key, value) in &tv_ratings {
        println!("{}\t: {}", key, value);
    }

    // 还可以可变地迭代,迭代的时候修改
    println!("All ratings with 100 as a maximum:");
    for (key, value) in &mut tv_ratings {
        *value *= 10;
        println!("{}\t: {}", key, value);
    }

    // 在不引用 HashMap 的情况下进行迭代会移动其内容
    for _ in tv_ratings {}
    // tv_ratings 不再可用

    // 与其他集合一样,可以预先分配容量大小以优化性能
    let mut age = HashMap::with_capacity(10);
    age.insert("Dory", 8);
    age.insert("Nemo", 3);
    age.insert("Merlin", 10);
    age.insert("Bruce", 9);

    // 迭代所有 key
    println!("All names:");
    for name in age.keys() {
        println!("{}", name);
    }

    // 迭代所有 value
    println!("All ages:");
    for age in age.values() {
        println!("{}", age);
    }

    // 迭代所有值并修改
    println!("All ages in 10 years");
    for age in age.values_mut() {
        *age += 10;
        println!("{}", age);
    }

    // 使用entry 为尚未在 HashMap 中的值分配默认值
    {
        let age_of_coral = age.entry("coral").or_insert(11);
        println!("age_of_coral: {}", age_of_coral);
    }
    let age_of_coral = age.entry("coral").or_insert(15);
    println!("age_of_coral: {}", age_of_coral);
}

results matching ""

    No results matching ""