在这几章的学习内容中,我认为最难理解的是虚拟地址页表那一章。一开始我一直困惑于“操作系统到底如何分配内存,如何知道地址是否合法的”,后来经过了解才知道,虚拟地址其实是软件和硬件共同实现的,操作系统需要做的是维护页表,而 cpu 会利用操作系统维护的页表,通过硬件来判断地址是否合法,以及将虚拟地址转换为真实的物理地址。所以整个计算机的发展软硬件是不可分开的。
letmut v = vec![1, 2, 3]; for i in v.iter_mut() { *i += 1; }
move_semantics2.rs
1 2 3 4 5 6 7 8
// move_semantics2.rs // // Expected output: // vec0 has length 3, with contents `[22, 44, 66]` // vec1 has length 4, with contents `[22, 44, 66, 88]` // // Execute `rustlings hint move_semantics2` or use the `hint` watch subcommand // for a hint.
// move_semantics4.rs // // Refactor this code so that instead of passing `vec0` into the `fill_vec` // function, the Vector gets created in the function itself and passed back to // the main function. // // Execute `rustlings hint move_semantics4` or use the `hint` watch subcommand // for a hint.
fnmain() { // let vec0 = Vec::new();
letmut vec1 = fill_vec();
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
vec1.push(88);
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); }
// `fill_vec()` no longer takes `vec: Vec<i32>` as argument fnfill_vec() -> Vec<i32> { letmut vec = Vec::new();
Unlike functions, methods are defined within the context of a struct,and their first parameter is always self, which represents the instance of the struct the method is being called on.
we still need to use the & in front of the self shorthand to indicate that this method borrows the Self instance, just as we did in rectangle: &Rectangle. Methods can take ownership of self, borrow selfimmutably, as we’ve done here, or borrow selfmutably, just as they can any other parameter.
// structs3.rs // // Structs contain data, but can also have logic. In this exercise we have // defined the Package struct and we want to test some logic attached to it. // Make the code compile and the tests pass! // // Execute `rustlings hint structs3` or use the `hint` watch subcommand for a // hint.
// enums3.rs // // Address all the TODOs to make the tests pass! // // Execute `rustlings hint enums3` or use the `hint` watch subcommand for a // hint.
// I AM NOT DONE
enumMessage { // TODO: implement the message variant types based on their usage below ChangeColor(u8, u8, u8), Echo(String), Move(Point), Quit }
fnprocess(&mutself, message: Message) { // TODO: create a match expression to process the different message // variants // Remember: When passing a tuple as a function argument, you'll need // extra parentheses: fn function((t, u, p, l, e)) // 模式匹配message match message { // 结构枚举类型绑定的值,相当于还完成了语句:Message::ChangeColor(r,g,b)=message Message::ChangeColor(r, g, b) => { self.change_color((r, g, b)); } Message::Echo(text) => { self.echo(text); }, Message::Move(point) => { self.move_position(point); } Message::Quit => { self.quit(); } } } }
#[test] fnreplace_a_string() { assert_eq!(replace_me("I think cars are cool"), "I think balloons are cool"); assert_eq!(replace_me("I love to look at cars"), "I love to look at balloons"); } }
hashmaps2.rs
问题1:
关于hashmap的更新实例中:为什么修改count的值就可以修改hashmap的键值呢?
1 2 3 4 5 6 7 8 9 10 11 12
use std::collections::HashMap;
let text = "hello world wonderful world";
letmut map = HashMap::new(); // 根据空格来切分字符串(英文单词都是通过空格切分) for word in text.split_whitespace() { let count = map.entry(word).or_insert(0); *count += 1; }
// quiz2.rs // // This is a quiz for the following sections: // - Strings // - Vecs // - Move semantics // - Modules // - Enums // // Let's build a little machine in the form of a function. As input, we're going // to give a list of strings and commands. These commands determine what action // is going to be applied to the string. It can either be: // - Uppercase the string // - Trim the string // - Append "bar" to the string a specified amount of times // The exact form of this will be: // - The input is going to be a Vector of a 2-length tuple, // the first element is the string, the second one is the command. // - The output element is going to be a Vector of strings. // // No hints this time!
// options2.rs // // Execute `rustlings hint options2` or use the `hint` watch subcommand for a // hint.
#[cfg(test)] mod tests { #[test] fnsimple_option() { let target = "rustlings"; let optional_target = Some(target);
// TODO: Make this an if let statement whose value is "Some" type ifletSome(word) = optional_target { assert_eq!(word, target); } }
#[test] fnlayered_option() { let range = 10; letmut optional_integers: Vec<Option<i8>> = vec![None];
for i in1..(range + 1) { optional_integers.push(Some(i)); }
letmut cursor = range;
// TODO: make this a while let statement - remember that vector.pop also // adds another layer of Option<T>. You can stack `Option<T>`s into // while let and if let. whileletSome(Some(integer)) = optional_integers.pop() { assert_eq!(integer, cursor); cursor -= 1; }
// errors2.rs // // Say we're writing a game where you can buy items with tokens. All items cost // 5 tokens, and whenever you purchase items there is a processing fee of 1 // token. A player of the game will type in how many items they want to buy, and // the `total_cost` function will calculate the total cost of the tokens. Since // the player typed in the quantity, though, we get it as a string-- and they // might have typed anything, not just numbers! // // Right now, this function isn't handling the error case at all (and isn't // handling the success case properly either). What we want to do is: if we call // the `parse` function on a string that is not a number, that function will // return a `ParseIntError`, and in that case, we want to immediately return // that error from our function and not try to multiply and add. // // There are at least two ways to implement this that are both correct-- but one // is a lot shorter! // // Execute `rustlings hint errors2` or use the `hint` watch subcommand for a // hint.
// I AM NOT DONE
use std::num::ParseIntError;
pubfntotal_cost(item_quantity: &str) -> Result<i32, ParseIntError> { let processing_fee = 1; let cost_per_item = 5; let qty = item_quantity.parse::<i32>(); // 如果parse()转换成功,qty将会是一个Result::Ok(qty) // 如果parse()转换失败,qty将会是一个Result::Err(ParseIntError) match qty { Ok(qty) => Ok(qty * cost_per_item + processing_fee), Err(ParseIntError) => Err(ParseIntError) } }
// errors3.rs // // This is a program that is trying to use a completed version of the // `total_cost` function from the previous exercise. It's not working though! // Why not? What should we do to fix it? // // Execute `rustlings hint errors3` or use the `hint` watch subcommand for a // hint.
fnnew(value: i64) -> Result<PositiveNonzeroInteger, CreationError> { match value { x if x < 0 => Err(CreationError::Negative), x if x == 0 => Err(CreationError::Zero), x => Ok(PositiveNonzeroInteger(x asu64)), } }
但感觉这里也可以直接if判断:
1 2 3 4 5 6 7
if value > 0 { Ok(PositiveNonzeroInteger(value asu64)) } elseif value < 0 { Err(CreationError::Negative) } else { Err(CreationError::Zero) }
// errors6.rs // // Using catch-all error types like `Box<dyn error::Error>` isn't recommended // for library code, where callers might want to make decisions based on the // error content, instead of printing it out or propagating it further. Here, we // define a custom error type to make it possible for callers to decide what to // do next when our function returns an error. // // Execute `rustlings hint errors6` or use the `hint` watch subcommand for a // hint.
use std::num::ParseIntError;
// This is a custom error type that we will be using in `parse_pos_nonzero()`. #[derive(PartialEq, Debug)] enumParsePosNonzeroError { Creation(CreationError), ParseInt(ParseIntError), }
fnparse_pos_nonzero(s: &str) -> Result<PositiveNonzeroInteger, ParsePosNonzeroError> { // TODO: change this to return an appropriate error instead of panicking // when `parse()` returns an error.
impl PositiveNonzeroInteger { fnnew(value: i64) -> Result<PositiveNonzeroInteger, CreationError> { match value { x if x < 0 => Err(CreationError::Negative), x if x == 0 => Err(CreationError::Zero), x => Ok(PositiveNonzeroInteger(x asu64)), } } }
#[cfg(test)] mod test { use super::*;
#[test] fntest_parse_error() { // We can't construct a ParseIntError, so we have to pattern match. assert!(matches!( parse_pos_nonzero("not a number"), Err(ParsePosNonzeroError::ParseInt(_)) )); }
// generics2.rs // // This powerful wrapper provides the ability to store a positive integer value. // Rewrite it using generics so that it supports wrapping ANY type. // // Execute `rustlings hint generics2` or use the `hint` watch subcommand for a // hint.
// traits5.rs // // Your task is to replace the '??' sections so the code compiles. // // Don't change any line other than the marked one. // // Execute `rustlings hint traits5` or use the `hint` watch subcommand for a // hint.
// quiz3.rs // // This quiz tests: // - Generics // - Traits // // An imaginary magical school has a new report card generation system written // in Rust! Currently the system only supports creating report cards where the // student's grade is represented numerically (e.g. 1.0 -> 5.5). However, the // school also issues alphabetical grades (A+ -> F-) and needs to be able to // print both types of report card! // // Make the necessary code changes in the struct ReportCard and the impl block // to support alphabetical report cards. Change the Grade in the second test to // "A+" to show that your changes allow alphabetical grades. // // Execute `rustlings hint quiz3` or use the `hint` watch subcommand for a hint.
#[test] fngenerate_numeric_report_card() { let report_card = ReportCard { grade: 2.1, student_name: "Tom Wriggle".to_string(), student_age: 12, }; assert_eq!( report_card.print(), "Tom Wriggle (12) - achieved a grade of 2.1" ); }
#[test] fngenerate_alphabetic_report_card() { // TODO: Make sure to change the grade here after you finish the exercise. let report_card = ReportCard { grade: String::from("A+"), student_name: "Gary Plotter".to_string(), student_age: 11, }; assert_eq!( report_card.print(), "Gary Plotter (11) - achieved a grade of A+" ); } }
fnmain() { let novel = String::from("Call me Ishmael. Some years ago..."); let first_sentence = novel.split('.').next().expect("Could not find a '.'"); let i = ImportantExcerpt { part: first_sentence, }; }
pubfnfactorial(num: u64) -> u64 { // Complete this function to return the factorial of num // Do not use: // - return // Try not to use: // - imperative style loops (for, while) // - additional variables // For an extra challenge, don't use: // - recursion // Execute `rustlings hint iterators4` for hints. (1..=num).product() }
fnmain() { // 创建handles,用以存储后面10个线程的句柄 letmut handles = vec![]; // 通过循环创建了10个线程,每个线程会执行一个闭包 for i in0..10 { // 使用move拿走当前i的所有权 handles.push(thread::spawn(move || { let start = Instant::now(); thread::sleep(Duration::from_millis(250)); // 250ms后输出,因为i的所有权被拿到了,因此可以访问i println!("thread {} is complete", i); start.elapsed().as_millis() })); } // 创建results,用以存储10个线程的执行时间 letmut results: Vec<u128> = vec![]; for handle in handles { // TODO: a struct is returned from thread::spawn, can you use it? // 等待每个线程执行完成再结束主线程 results.push(handle.join().unwrap()); } // 输出时间 for (i, result) in results.into_iter().enumerate() { println!("thread {} took {}ms", i, result); } }
fnsend_tx(q: Queue, tx: mpsc::Sender<u32>) -> () { let qc = Arc::new(q); let qc1 = Arc::clone(&qc); let qc2 = Arc::clone(&qc); // 克隆发送方 let tx_clone = tx.clone();
thread::spawn(move || { for val in &qc1.first_half { println!("sending {:?}", val); tx.send(*val).unwrap(); thread::sleep(Duration::from_secs(1)); } });
thread::spawn(move || { for val in &qc2.second_half { println!("sending {:?}", val); // 使用克隆的发送方 tx_clone.send(*val).unwrap(); thread::sleep(Duration::from_secs(1)); } }); }
#[rustfmt::skip] macro_rules! my_macro { () => { println!("Check out my macro!"); }; ($val:expr) => { println!("Look at this other macro: {}", $val); }; }
fnmain() { my_macro!(); my_macro!(7777); }
匹配多次:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#[rustfmt::skip] macro_rules! my_macro { () => { println!("Check out my macro!"); }; ($($val:expr),*) => { $( println!("Look at this other macro: {}", $val); )* }; }
// Insert a value into the BST fninsert(&mutself, value: T) { // 直接使用节点的插入方法 match &mutself.root { Some(root_node) => { root_node.insert(value); } _ => { self.root = Some(Box::new(TreeNode::new(value))); } } }
1 2 3 4 5 6 7
// Search for a value in the BST fnsearch(&self, value: T) -> bool { match &self.root { Some(root_node) => { root_node.search(value) } _ => { false } } }
// 按堆规定的顺序返回两个孩子中应该在前面的一个的索引值 fnsmallest_child_idx(&self, idx: usize) -> usize { let left = self.left_child_idx(idx); let right = self.right_child_idx(idx); if right > self.count { left } elseif (self.comparator)(&self.items[left], &self.items[right]) { left } else { right } } }