Rust语言圣经(Rust教程 Rust Course和配套练习)

【strings4.rs】

fn string_slice(arg: &str) {println!("{}", arg);
}
fn string(arg: String) {println!("{}", arg);
}fn main() {string_slice("blue");string("red".to_string());string(String::from("hi"));string("rust is fun!".to_owned());string("nice weather".into());string(format!("Interpolation {}", "Station"));string_slice(&String::from("abc")[0..1]);string_slice("  hello there ".trim());string("Happy Monday!".to_string().replace("Mon", "Tues"));string("mY sHiFt KeY iS sTiCkY".to_lowercase());
}
  • // 构造一个string
    String::from("hi")
    
  • // "xxx".to_owned()方法内部掉clone(),将字符串字面量从ROData区复制一份到堆上,并返回堆上数据的所有权;String::from("xxx")内部实际调用的是"xxx".to_owned();
    "rust is fun!".to_owned()
    
  • // 如果可以推断类型使用.into
    "nice weather".into()
    
  • // pub fn trim(&self) -> &str
    // 返回删除了前导和尾随空格的字符串切片。
    
  • // pub fn to_lowercase(&self) -> String
    // 返回此字符串切片的小写等效项,作为新的 String
    

【modules1.rs】

Rust 出于安全的考虑,默认情况下,所有的类型都是私有化的,包括函数、方法、结构体、枚举、常量,是的,就连模块本身也是私有化的。通过pub关键字使得模块内函数可见。

【modules2.rs】

使用 use … as … 关键字可以给模块起别名,注意要给 use 前加 pub 可以使得变成可见的

【modules3.rs】

使用use关键字两个外部模块放在一起

use std::time::{SystemTime , UNIX_EPOCH};

【hashmaps1.rs】

通过 HashMap::new(); 创建HashMap,通过basket.insert(String::from("apple"), 3);方法增加

【hashmaps2.rs】

通过匹配对应的两种水果是否是这两种分别进行判断,如果两种水果是这两种的话,再判断里面的值是否是空,是的话赋值。

  • if匹配的时候enum类似要加上前面的类型::
  • option的空为None

【hashmaps3.rs】

刚开始获取原始的值,之后分别创建传输的结构体,原始值不为0则调用相加,否则不管。

  • 可借用和不可借用之间可以通过调换顺序可以避免报错。
  • 注意多看看人家的提示,panic会有相应的解释和对应的行数

【quiz2.rs】

  • Vec类型可以与元组进行复合变成:input: Vec<(String,Command)>

  • Vec类型必须在中扩展中加入内部存储的类型描述

  • .iter()代表一个迭代器

  • 变大写字母:output.push(string.to_uppercase())

  • 去掉前面后面的空格;output.push(string.trim().to_string())

  • 面对不可变引用的可变操作,可以整个变量替代他

    Command::Append(i) => {let mut sa = string.to_string();for n in 0..*i{sa.push_str("bar");}output.push(sa.to_string());}
    

【options1.rs】

看完TODO

【options2.rs】

  • if let 匹配一个分支

    if let Some(word) = optional_word {println!("The word is: {}", word);}
    
  • while let 只要模式匹配就一直进行 while 循环

    while let Some(integer) = optional_integers_vec.pop() {println!("current value: {:?}", integer);}
    

【options3.rs】

不想让Option结束声明周期就用&

match &y {Some(p) => println!("Co-ordinates are {},{} ", p.x, p.y),_ => println!("no match"),}
y; // Fix without deleting this line.

【errors1.rs】

  • assert_eq! 需要左右两个参数的类型相同

  • ok and err,这两个方法可以将Result类型转化为Option类型

    pub fn ok(self) -> Option<T>
    pub fn err(self) -> Option<E>
    
  • ok_or和ok_or_else,这两个是一组,作用都是从Option转成Result。

    pub fn ok_or<E>(self, err: E) -> Result<T, E>pub fn ok_or_else<E, F>(self, err: F) -> Result<T, E>
    whereF: FnOnce() -> E,
    

Option和Result相关的组合算子 (bean-li.github.io)

【errors2.rs】

pub fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {let processing_fee = 1;let cost_per_item = 5;let qty = item_quantity.parse::<i32>();let mut f = match qty {Ok(file) => return Ok(file* cost_per_item + processing_fee),Err(e) => return Err(e),};//Ok(qty * cost_per_item + processing_fee)
}
  • 本题是错误传递,要将正确的和错误的都传出来

  • parse:它定义在 std:str 下面,他把这个字符串切片解析成另外一种类型。

【errors3.rs】

  • 其实 ? 就是一个宏,它的作用跟上面的 match 几乎一模一样,但他可以做返回类型Err的隐式转换
  • ?操作符只能如下两种样子使用,必须带变量承载值
    • let v = xxx()?;
    • xxx()?.yyy()?;
  • 主函数也会有返回值,最后必须需要一个返回的东西
use std::num::ParseIntError;fn main() -> Result<(), ParseIntError>{let mut tokens = 100;let pretend_user_input = "8";let cost = total_cost(pretend_user_input)?;if cost > tokens {println!("You can't afford that many!");} else {tokens -= cost;println!("You now have {} tokens.", tokens);}Ok(())
}pub fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {let processing_fee = 1;let cost_per_item = 5;let qty = item_quantity.parse::<i32>() ? * cost_per_item + processing_fee;Ok(qty)
}

【errors4.rs】

  • 返回的结果是Ok还是Err是我们定的,所以我们可以通过个人定义的逻辑判断判断正误来返回结果

    #[derive(PartialEq, Debug)]
    struct PositiveNonzeroInteger(u64);#[derive(PartialEq, Debug)]
    enum CreationError {Negative,Zero,
    }impl PositiveNonzeroInteger {fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {// Hmm...? Why is this only returning an Ok value?if value > 0{Ok(PositiveNonzeroInteger(value as u64))}else if value == 0{Err(CreationError::Zero)}else {Err(CreationError::Negative)}}
    }#[test]
    fn test_creation() {assert!(PositiveNonzeroInteger::new(10).is_ok());assert_eq!(Err(CreationError::Negative),PositiveNonzeroInteger::new(-10));assert_eq!(Err(CreationError::Zero), PositiveNonzeroInteger::new(0));
    }
    

【errors5.rs】

use std::error;
use std::fmt;
use std::num::ParseIntError;// TODO: update the return type of `main()` to make this compile.
fn main() -> Result<(), Box<dyn error::Error>> {let pretend_user_input = "42";let x: i64 = pretend_user_input.parse()?;println!("output={:?}", PositiveNonzeroInteger::new(x)?);Ok(())
}// Don't change anything below this line.#[derive(PartialEq, Debug)]
struct PositiveNonzeroInteger(u64);#[derive(PartialEq, Debug)]
enum CreationError {Negative,Zero,
}impl PositiveNonzeroInteger {fn new(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 as u64))}}
}// This is required so that `CreationError` can implement `error::Error`.
impl fmt::Display for CreationError {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {let description = match *self {CreationError::Negative => "number is negative",CreationError::Zero => "number is zero",};f.write_str(description)}
}impl error::Error for CreationError {}

返回的Err属于实现了某个trait的类型

【errors6.rs】

use std::num::ParseIntError;// This is a custom error type that we will be using in `parse_pos_nonzero()`.
#[derive(PartialEq, Debug)]
enum ParsePosNonzeroError {Creation(CreationError),ParseInt(ParseIntError)
}impl ParsePosNonzeroError {fn from_creation(err: CreationError) -> ParsePosNonzeroError {ParsePosNonzeroError::Creation(err)}// TODO: add another error conversion function here.fn from_parseint(err: ParseIntError) -> ParsePosNonzeroError {ParsePosNonzeroError::ParseInt(err)}
}fn parse_pos_nonzero(s: &str)-> Result<PositiveNonzeroInteger, ParsePosNonzeroError>
{// TODO: change this to return an appropriate error instead of panicking// when `parse()` returns an error.let x = s.parse();let mut f = match x{Ok(x) => {return PositiveNonzeroInteger::new(x).map_err(ParsePosNonzeroError::from_creation);},Err(e) => return  Err(ParsePosNonzeroError::ParseInt(e)),};
}// Don't change anything below this line.#[derive(PartialEq, Debug)]
struct PositiveNonzeroInteger(u64);#[derive(PartialEq, Debug)]
enum CreationError {Negative,Zero,
}impl PositiveNonzeroInteger {fn new(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 as u64))}}
}#[cfg(test)]
mod test {use super::*;#[test]fn test_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(_))));}#[test]fn test_negative() {assert_eq!(parse_pos_nonzero("-555"),Err(ParsePosNonzeroError::Creation(CreationError::Negative)));}#[test]fn test_zero() {assert_eq!(parse_pos_nonzero("0"),Err(ParsePosNonzeroError::Creation(CreationError::Zero)));}#[test]fn test_positive() {let x = PositiveNonzeroInteger::new(42);assert!(x.is_ok());assert_eq!(parse_pos_nonzero("42"), Ok(x.unwrap()));}
}
  • 多了个错误外层的判断

【generics1.rs】

fn main() {let mut shopping_list: Vec<String> = Vec::new();shopping_list.push("milk".to_string());
}
  • Vec类型要设定

【generics2.rs】

//struct类型的泛型定义
struct Wrapper <T>{value: T,
}
//方法的泛型定义
impl <T> Wrapper <T>{pub fn new(value: T) -> Self {Wrapper { value }}
}#[cfg(test)]
mod tests {use super::*;#[test]fn store_u32_in_wrapper() {assert_eq!(Wrapper::new(42).value, 42);}#[test]fn store_str_in_wrapper() {assert_eq!(Wrapper::new("Foo").value, "Foo");}
}

【traits1.rs】

// The trait AppendBar has only one function,
// which appends "Bar" to any object
// implementing this trait.
// Execute `rustlings hint traits1` or use the `hint` watch subcommand for a hint.
trait AppendBar {fn append_bar(self) -> Self;
}
//实现这个Trait,返回追加的字符串
impl AppendBar for String {//Add your code herefn append_bar(self) -> Self{self+"Bar"}
}fn main() {let s = String::from("Foo");let s = s.append_bar();println!("s: {}", s);
}#[cfg(test)]
mod tests {use super::*;#[test]fn is_foo_bar() {assert_eq!(String::from("Foo").append_bar(), String::from("FooBar"));}#[test]fn is_bar_bar() {assert_eq!(String::from("").append_bar().append_bar(),String::from("BarBar"));}
}

【traits2.rs】

trait AppendBar {fn append_bar(self) -> Self;
}//TODO: Add your code here
impl AppendBar for Vec<String>{fn append_bar(mut self) -> Vec<String>{self.push("Bar".to_string());self}
}#[cfg(test)]
mod tests {use super::*;#[test]fn is_vec_pop_eq_bar() {let mut foo = vec![String::from("Foo")].append_bar();assert_eq!(foo.pop().unwrap(), String::from("Bar"));assert_eq!(foo.pop().unwrap(), String::from("Foo"));}
}
  • 先完成push这个操作,再返回self,要不会报返回类型不匹配的问题

    expected struct Vec, found ()

  • 传入可变的self才能修改

【traits3.rs】

//具有默认实现的方法其它类型无需再实现该方法,或者也可以选择重载该方法
pub trait Licensed {fn licensing_info(&self) -> String{"Some information".to_string()}
}struct SomeSoftware {version_number: i32,
}struct OtherSoftware {version_number: String,
}impl Licensed for SomeSoftware {} // Don't edit this line
impl Licensed for OtherSoftware {} // Don't edit this line#[cfg(test)]
mod tests {use super::*;#[test]fn is_licensing_info_the_same() {let licensing_info = String::from("Some information");let some_software = SomeSoftware { version_number: 1 };let other_software = OtherSoftware {version_number: "v2.0.0".to_string(),};assert_eq!(some_software.licensing_info(), licensing_info);assert_eq!(other_software.licensing_info(), licensing_info);}
}

【traits4.rs】

pub trait Licensed {fn licensing_info(&self) -> String {"some information".to_string()}
}struct SomeSoftware {}struct OtherSoftware {}impl Licensed for SomeSoftware {}
impl Licensed for OtherSoftware {}//两个参数都实现了Licensed这个trait
fn compare_license_types(software: impl Licensed, software_two: impl Licensed) -> bool {software.licensing_info() == software_two.licensing_info()
}#[cfg(test)]
mod tests {use super::*;#[test]fn compare_license_information() {let some_software = SomeSoftware {};let other_software = OtherSoftware {};assert!(compare_license_types(some_software, other_software));}#[test]fn compare_license_information_backwards() {let some_software = SomeSoftware {};let other_software = OtherSoftware {};assert!(compare_license_types(other_software, some_software));}
}

【traits5.rs】

pub trait SomeTrait {fn some_function(&self) -> bool {true}
}pub trait OtherTrait {fn other_function(&self) -> bool {true}
}struct SomeStruct {name: String,
}impl SomeTrait for SomeStruct {}
impl OtherTrait for SomeStruct {}//同一个类型实现了两个trait的约束
fn some_func<T: OtherTrait + SomeTrait>(item: T) -> bool {item.some_function() && item.other_function()
}fn main() {}

【quiz3.rs】

pub struct ReportCard<T>{pub grade: T,pub student_name: String,pub student_age: u8,
}impl <T:std::fmt::Display> ReportCard <T> {pub fn print(&self) -> String {format!("{} ({}) - achieved a grade of ",&self.student_name, &self.student_age) + &self.grade.to_string()}
}#[cfg(test)]
mod tests {use super::*;#[test]fn generate_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]fn generate_alphabetic_report_card() {// TODO: Make sure to change the grade here after you finish the exercise.let report_card = ReportCard {grade: "A+",student_name: "Gary Plotter".to_string(),student_age: 11,};assert_eq!(report_card.print(),"Gary Plotter (11) - achieved a grade of A+");}
}
  • 匹配不同的两个类型使用泛型
  • T:std::fmt::Display要实现了这种方法的可以进行后续的匹配

【test1.rs】

#[cfg(test)]
mod tests {#[test]fn you_can_assert() {assert!(true,true);}
}

【test2.rs】

#[cfg(test)]
mod tests {#[test]fn you_can_assert_eq() {assert_eq!(true,true);}
}

【test3.rs】

pub fn is_even(num: i32) -> bool {num % 2 == 0
}#[cfg(test)]
mod tests {use super::*;#[test]fn is_true_when_even() {assert!(is_even(4));}
//当断言是错误的时候可以使用assert!(! )#[test]fn is_false_when_odd() {assert!(!is_even(5));}
}

【lifetimes1.rs】

//设定两个的生命周期一样长
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {if x.len() > y.len() {x} else {y}
}fn main() {let string1 = String::from("abcd");let string2 = "xyz";let result = longest(string1.as_str(), string2);println!("The longest string is {}", result);
}

【lifetimes2.rs】

fn longest (x: String, y: String) -> String {if &x.len() > &y.len() {x} else {y}
}fn main() {let string1 = String::from("long string is long");let result;{//直接将生命周期传进去let string2 = String::from("xyz");result = longest(string1, string2);}println!("The longest string is {}", result);
}

【lifetimes3.rs】

//结构体的生命周期表面该传入的str比这个结构体活得长
struct Book <'a>{author: &'a str,title:  &'a str,
}fn main() {let name = String::from("Jill Smith");let title = String::from("Fish Flying");let book = Book { author: &name, title: &title };println!("{} by {}", book.title, book.author);
}

【iterators1.rs】

fn main () {let my_fav_fruits = vec!["banana", "custard apple", "avocado", "peach", "raspberry"];//创建迭代器let mut my_iterable_fav_fruits = my_fav_fruits.iter(); // TODO: Step 1//不断迭代,next 方法返回的是Option类型,没有为Noneassert_eq!(my_iterable_fav_fruits.next(), Some(&"banana"));assert_eq!(my_iterable_fav_fruits.next(), Some(&"custard apple"));     // TODO: Step 2assert_eq!(my_iterable_fav_fruits.next(), Some(&"avocado"));assert_eq!(my_iterable_fav_fruits.next(), Some(&"peach"));     // TODO: Step 3assert_eq!(my_iterable_fav_fruits.next(), Some(&"raspberry"));assert_eq!(my_iterable_fav_fruits.next(), None);     // TODO: Step 4
}

【iterators2.rs】

// Step 1.
// Complete the `capitalize_first` function.
// "hello" -> "Hello"
pub fn capitalize_first(input: &str) -> String {let mut c = input.chars();match c.next() {None => String::new(),//取第一个字符的大写再拼接后面的Some(first) => {let up = first.to_string().to_uppercase();up + &input[1..]}}
}// Step 2.
// Apply the `capitalize_first` function to a slice of string slices.
// Return a vector of strings.
// ["hello", "world"] -> ["Hello", "World"]
// 使用迭代器进行遍历调用
pub fn capitalize_words_vector(words: &[&str]) -> Vec<String> {let mut numbers: Vec<String> = vec![];for i in words{numbers.push(capitalize_first(i));}numbers
}// Step 3.
// Apply the `capitalize_first` function again to a slice of string slices.
// Return a single string.
// ["hello", " ", "world"] -> "Hello World"
pub fn capitalize_words_string(words: &[&str]) -> String {let mut S = String::new();for i in words{S.push_str(&capitalize_first(&i));}S
}#[cfg(test)]
mod tests {use super::*;#[test]fn test_success() {assert_eq!(capitalize_first("hello"), "Hello");}#[test]fn test_empty() {assert_eq!(capitalize_first(""), "");}#[test]fn test_iterate_string_vec() {let words = vec!["hello", "world"];assert_eq!(capitalize_words_vector(&words), ["Hello", "World"]);}#[test]fn test_iterate_into_string() {let words = vec!["hello", " ", "world"];assert_eq!(capitalize_words_string(&words), "Hello World");}
}

【iterators3.rs】

#[derive(Debug, PartialEq, Eq)]
pub enum DivisionError {NotDivisible(NotDivisibleError),DivideByZero,
}#[derive(Debug, PartialEq, Eq)]
pub struct NotDivisibleError {dividend: i32,divisor: i32,
}// Calculate `a` divided by `b` if `a` is evenly divisible by `b`.
// Otherwise, return a suitable error.
pub fn divide(a: i32, b: i32) -> Result<i32, DivisionError> {if b == 0{let x = Err(DivisionError::DivideByZero);return x;}if a % b == 0{Ok(a/b) }else {Err(DivisionError::NotDivisible(NotDivisibleError {dividend: 81,divisor: 6}))}}// Complete the function and return a value of the correct type so the test passes.
// Desired output: Ok([1, 11, 1426, 3])
fn result_with_list() -> Result<Vec<i32>,DivisionError> {let mut buff:Vec<i32> = vec![];let numbers = vec![27, 297, 38502, 81];let division_results = numbers.into_iter().map(|n| divide(n, 27));for i in division_results{match i {Ok(v) => buff.push(v),_ => buff.push(0),}}let mut num:Result<Vec<i32>,DivisionError> = Ok(buff);num
}// Complete the function and return a value of the correct type so the test passes.
// Desired output: [Ok(1), Ok(11), Ok(1426), Ok(3)]
fn list_of_results() -> Vec<Result<i32,DivisionError>> {let mut num:Vec<Result<i32,DivisionError>> = vec![];let numbers = vec![27, 297, 38502, 81];let division_results = numbers.into_iter().map(|n| divide(n, 27));for i in division_results{match i {Ok(v) => num.push(Ok(v)),Err(e) => num.push(Err(e)),}}num
}#[cfg(test)]
mod tests {use super::*;#[test]fn test_success() {assert_eq!(divide(81, 9), Ok(9));}#[test]fn test_not_divisible() {assert_eq!(divide(81, 6),Err(DivisionError::NotDivisible(NotDivisibleError {dividend: 81,divisor: 6})));}#[test]fn test_divide_by_0() {assert_eq!(divide(81, 0), Err(DivisionError::DivideByZero));}#[test]fn test_divide_0_by_something() {assert_eq!(divide(0, 81), Ok(0));}#[test]fn test_result_with_list() {assert_eq!(format!("{:?}", result_with_list()), "Ok([1, 11, 1426, 3])");}#[test]fn test_list_of_results() {assert_eq!(format!("{:?}", list_of_results()),"[Ok(1), Ok(11), Ok(1426), Ok(3)]");}
}
  • divide

    • 首先判断b的类型,如果是0则直接退出
    • 后面判断是否可以整除,可以的话就直接返回结果,否则返回定义的错误
  • result_with_list
    • Ok([1, 11, 1426, 3]) 从返回的类型判断是Result类型复合Vec
    • 先获得数组的值,再赋给Result类型进行返回
  • list_of_results
    • [Ok(1), Ok(11), Ok(1426), Ok(3)] 从返回的类型判断是Vec类型复合Result
    • 直接创建这个Vec然后进行一个个push

【iterators4.rs】

pub fn factorial(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.(1u64..num+1).into_iter().fold(1u64, |sum, acm| sum * acm)
}#[cfg(test)]
mod tests {use super::*;#[test]fn factorial_of_0() {assert_eq!(1, factorial(0));}#[test]fn factorial_of_1() {assert_eq!(1, factorial(1));}#[test]fn factorial_of_2() {assert_eq!(2, factorial(2));}#[test]fn factorial_of_4() {assert_eq!(24, factorial(4));}
}
  • 通过range产生连续的数值
  • 通过fold函数进行累积

【box1.rs】

#[derive(PartialEq, Debug)]
pub enum List {Cons(i32, Box<List>),Nil,
}fn main() {println!("This is an empty cons list: {:?}", create_empty_list());println!("This is a non-empty cons list: {:?}",create_non_empty_list());
}pub fn create_empty_list() -> List {let n  = List::Nil;n
}pub fn create_non_empty_list() -> List {let n  = List::Cons(32,Box::new(List::Nil));n
}#[cfg(test)]
mod tests {use super::*;#[test]fn test_create_empty_list() {assert_eq!(List::Nil, create_empty_list())}#[test]fn test_create_non_empty_list() {assert_ne!(create_empty_list(), create_non_empty_list())}
}
  • 通过Box可以将内存分配在堆上
  • 递归类型可以使用Box< T >使得动态大小类型变成固定大小类型(将 List 存储到堆上,然后使用一个智能指针指向它)。

【arc1.rs】

#![forbid(unused_imports)] // Do not change this, (or the next) line.
use std::sync::Arc;
use std::thread;fn main() {let numbers: Vec<_> = (0..100u32).collect();let shared_numbers = Arc::new(numbers);// TODOlet mut joinhandles = Vec::new();for offset in 0..8 {let child_numbers = Arc::clone(&shared_numbers);// TODOjoinhandles.push(thread::spawn(move || {let sum: u32 = child_numbers.iter().filter(|n| *n % 8 == offset).sum();println!("Sum of offset {} is {}", offset, sum);}));}for handle in joinhandles.into_iter() {handle.join().unwrap();}
}
  • 多个线程获得同一个数据,类似于多个指针

【threads2.rs】

use std::sync::Arc;
use std::thread;
use std::time::Duration;
use std::sync::Mutex;struct JobStatus {jobs_completed: u32,
}fn main() {let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));let mut handles = vec![];for _ in 0..10 {let status_shared = status.clone();let handle = thread::spawn(move || {thread::sleep(Duration::from_millis(250));// TODO: You must take an action before you update a shared valuelet mut num = status_shared.lock().unwrap();num.jobs_completed += 1;});handles.push(handle);}for handle in handles {handle.join().unwrap();// TODO: Print the value of the JobStatus.jobs_completed. Did you notice anything// interesting in the output? Do you have to 'join' on all the handles?println!("jobs completed {}", Arc::strong_count(&status));}
}

【threads3.rs】

use std::sync::mpsc;
use std::sync::Arc;
use std::thread;
use std::time::Duration;struct Queue {length: u32,first_half: Vec<u32>,second_half: Vec<u32>,
}impl Queue {fn new() -> Self {Queue {length: 10,first_half: vec![1, 2, 3, 4, 5],second_half: vec![6, 7, 8, 9, 10],}}
}fn send_tx(q: Queue, tx: mpsc::Sender<u32>) -> () {let qc = Arc::new(q);//由于子线程会拿走发送者的所有权,因此我们必须对发送者进行克隆,然后让每个线程拿走它的一份拷贝let tx1 = tx.clone();let qc1 = qc.clone();let qc2 = qc.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);tx1.send(*val).unwrap();thread::sleep(Duration::from_secs(1));}});
}fn main() {let (tx, rx) = mpsc::channel();let queue = Queue::new();let queue_length = queue.length;send_tx(queue, tx);let mut total_received: u32 = 0;for received in rx {println!("Got: {}", received);total_received += 1;}println!("total numbers received: {}", total_received);assert_eq!(total_received, queue_length)
}

【macros1.rs】

macro_rules! my_macro {() => {println!("Check out my macro!");};
}//使用宏的时候加!,定义的时候不用
fn main() {my_macro!();
}

【macros2.rs】

fn main() {my_macro!();
}
//#[macro_export] 注释将宏进行了导出,这样其它的包就可以将该宏引入到当前作用域中,然后才能使用。
#[macro_export]
macro_rules! my_macro {() => {println!("Check out my macro!");};
}

【macros3.rs】

mod macros {#[macro_export]macro_rules! my_macro {() => {println!("Check out my macro!");};}
}fn main() {my_macro!();
}

【macros4.rs】

macro_rules! my_macro {() => {println!("Check out my macro!");};( $val:expr ) => {println!("Look at this other macro: {}", $val);}
}fn main() {my_macro!();my_macro!(7777);
}

【clippy1.rs】

use std::f32;//使用官方的标准定义
fn main() {    let pi = std::f32::consts::PI;let radius = 5.00f32;let area = pi * f32::powi(radius, 2);println!("The area of a circle with radius {:.2} is {:.5}!",radius, area)
}

【clippy2.rs】

fn main() {let mut res = 42;let option = Some(12);if let Some(x) = option {res += x;}println!("{}", res);
}

【clippy3.rs】

#[allow(unused_variables, unused_assignments)]
fn main() {let my_option: Option<()> = None;my_option.unwrap() ;let my_arr = &[-1, -2, -3,-4, -5, -6];println!("My array! Here it is: {:?}", my_arr);let my_empty_vec = vec![0, 0, 0, 0, 0];println!("This Vec is empty, see? {:?}", my_empty_vec);let mut value_a = 45;let mut value_b = 66;// Let's swap these two!// value_a = value_b;// value_b = value_a;std::mem::swap(&mut value_a, &mut value_b);println!("value a: {}; value b: {}", value_a, value_b);
}

【using_as.rs】

fn average(values: &[f64]) -> f64 {let total = values.iter().sum::<f64>();//转换成同类型的值执行total / values.len() as f64
}fn main() {let values = [3.5, 0.3, 13.0, 11.7];println!("{}", average(&values));
}#[cfg(test)]
mod tests {use super::*;#[test]fn returns_proper_type_and_value() {assert_eq!(average(&[3.5, 0.3, 13.0, 11.7]), 7.125);}
}

【form_into.rs】

#[derive(Debug)]
struct Person {name: String,age: usize,
}// We implement the Default trait to use it as a fallback
// when the provided string is not convertible into a Person object
impl Default for Person {fn default() -> Person {Person {name: String::from("John"),age: 30,}}
}// Your task is to complete this implementation
// in order for the line `let p = Person::from("Mark,20")` to compile
// Please note that you'll need to parse the age component into a `usize`
// with something like `"4".parse::<usize>()`. The outcome of this needs to
// be handled appropriately.
//
// Steps:
// 1. If the length of the provided string is 0, then return the default of Person
// 2. Split the given string on the commas present in it
// 3. Extract the first element from the split operation and use it as the name
// 4. If the name is empty, then return the default of Person
// 5. Extract the other element from the split operation and parse it into a `usize` as the age
// If while parsing the age, something goes wrong, then return the default of Person
// Otherwise, then return an instantiated Person object with the results// I AM NOT DONEimpl From<&str> for Person {fn from(s: &str) -> Person {let mut x:Person =  Person::default();let mut n:Person =  Person::default();//空值判断if s == ""{return n;}//,判断let mut num = 0;for i in s.chars() {if i == ','{num +=1;}}if num != 1{return n;}//分割let v: Vec<&str> = s.split(",").collect();if (&v[0]).to_string() != ""{x.name = (&v[0]).to_string();}else {return n;}match v[1].parse::<usize>(){Ok(num) => x.age = num,Err(e) => return n,}x}
}fn main() {// Use the `from` functionlet p1 = Person::from("Mark,20");// Since From is implemented for Person, we should be able to use Intolet p2: Person = "Gerald,70".into();println!("{:?}", p1);println!("{:?}", p2);
}#[cfg(test)]
mod tests {use super::*;#[test]fn test_default() {// Test that the default person is 30 year old Johnlet dp = Person::default();assert_eq!(dp.name, "John");assert_eq!(dp.age, 30);}#[test]fn test_bad_convert() {// Test that John is returned when bad string is providedlet p = Person::from("");assert_eq!(p.name, "John");assert_eq!(p.age, 30);}#[test]fn test_good_convert() {// Test that "Mark,20" workslet p = Person::from("Mark,20");assert_eq!(p.name, "Mark");assert_eq!(p.age, 20);}#[test]fn test_bad_age() {// Test that "Mark,twenty" will return the default person due to an error in parsing agelet p = Person::from("Mark,twenty");assert_eq!(p.name, "John");assert_eq!(p.age, 30);}#[test]fn test_missing_comma_and_age() {let p: Person = Person::from("Mark");assert_eq!(p.name, "John");assert_eq!(p.age, 30);}#[test]fn test_missing_age() {let p: Person = Person::from("Mark,");assert_eq!(p.name, "John");assert_eq!(p.age, 30);}#[test]fn test_missing_name() {let p: Person = Person::from(",1");assert_eq!(p.name, "John");assert_eq!(p.age, 30);}#[test]fn test_missing_name_and_age() {let p: Person = Person::from(",");assert_eq!(p.name, "John");assert_eq!(p.age, 30);}#[test]fn test_missing_name_and_invalid_age() {let p: Person = Person::from(",one");assert_eq!(p.name, "John");assert_eq!(p.age, 30);}#[test]fn test_trailing_comma() {let p: Person = Person::from("Mike,32,");assert_eq!(p.name, "John");assert_eq!(p.age, 30);}#[test]fn test_trailing_comma_and_some_string() {let p: Person = Person::from("Mike,32,man");assert_eq!(p.name, "John");assert_eq!(p.age, 30);}
}

【from_str.rs】

use std::num::ParseIntError;
use std::str::FromStr;#[derive(Debug, PartialEq)]
struct Person {name: String,age: usize,
}// We will use this error type for the `FromStr` implementation.
#[derive(Debug, PartialEq)]
enum ParsePersonError {// Empty input stringEmpty,// Incorrect number of fieldsBadLen,// Empty name fieldNoName,// Wrapped error from parse::<usize>()ParseInt(ParseIntError),
}// I AM NOT DONE// Steps:
// 1. If the length of the provided string is 0, an error should be returned
// 2. Split the given string on the commas present in it
// 3. Only 2 elements should be returned from the split, otherwise return an error
// 4. Extract the first element from the split operation and use it as the name
// 5. Extract the other element from the split operation and parse it into a `usize` as the age
//    with something like `"4".parse::<usize>()`
// 6. If while extracting the name and the age something goes wrong, an error should be returned
// If everything goes well, then return a Result of a Person object
//
// As an aside: `Box<dyn Error>` implements `From<&'_ str>`. This means that if you want to return a
// string error message, you can do so via just using return `Err("my error message".into())`.impl FromStr for Person {type Err = ParsePersonError;fn from_str(s: &str) -> Result<Person, Self::Err> {let mut x:Person =  Person {name: String::from("John"),age: 30,};let mut n:Person =  Person {name: String::from("John"),age: 30,};//空值判断if s == ""{return Err(ParsePersonError::Empty);}//,判断let mut num = 0;for i in s.chars() {if i == ','{num +=1;}}if num != 1{return Err(ParsePersonError::BadLen);}//分割let v: Vec<&str> = s.split(",").collect();if (&v[0]).to_string() != ""{x.name = (&v[0]).to_string();}else {return Err(ParsePersonError::NoName);}match v[1].parse::<usize>(){Ok(num) => x.age = num,Err(e) => return Err(ParsePersonError::ParseInt(e)) ,}Ok(x)}
}fn main() {let p = "Mark,20".parse::<Person>().unwrap();println!("{:?}", p);
}#[cfg(test)]
mod tests {use super::*;#[test]fn empty_input() {assert_eq!("".parse::<Person>(), Err(ParsePersonError::Empty));}#[test]fn good_input() {let p = "John,32".parse::<Person>();assert!(p.is_ok());let p = p.unwrap();assert_eq!(p.name, "John");assert_eq!(p.age, 32);}#[test]fn missing_age() {assert!(matches!("John,".parse::<Person>(),Err(ParsePersonError::ParseInt(_))));}#[test]fn invalid_age() {assert!(matches!("John,twenty".parse::<Person>(),Err(ParsePersonError::ParseInt(_))));}#[test]fn missing_comma_and_age() {assert_eq!("John".parse::<Person>(), Err(ParsePersonError::BadLen));}#[test]fn missing_name() {assert_eq!(",1".parse::<Person>(), Err(ParsePersonError::NoName));}#[test]fn missing_name_and_age() {assert!(matches!(",".parse::<Person>(),Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_))));}#[test]fn missing_name_and_invalid_age() {assert!(matches!(",one".parse::<Person>(),Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_))));}#[test]fn trailing_comma() {assert_eq!("John,32,".parse::<Person>(), Err(ParsePersonError::BadLen));}#[test]fn trailing_comma_and_some_string() {assert_eq!("John,32,man".parse::<Person>(),Err(ParsePersonError::BadLen));}
}

【try_from_into.rs】

use std::convert::{TryFrom, TryInto};#[derive(Debug, PartialEq)]
struct Color {red: u8,green: u8,blue: u8,
}// We will use this error type for these `TryFrom` conversions.
#[derive(Debug, PartialEq)]
enum IntoColorError {// Incorrect length of sliceBadLen,// Integer conversion errorIntConversion,
}// I AM NOT DONE// Your task is to complete this implementation
// and return an Ok result of inner type Color.
// You need to create an implementation for a tuple of three integers,
// an array of three integers, and a slice of integers.
//
// Note that the implementation for tuple and array will be checked at compile time,
// but the slice implementation needs to check the slice length!
// Also note that correct RGB color values must be integers in the 0..=255 range.// Tuple implementation
impl TryFrom<(i16, i16, i16)> for Color {type Error = IntoColorError;fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> {let mut c = Color { red: 0, green: 0, blue: 0 };if tuple.0 < 0 || tuple.0>255{return Err(IntoColorError::IntConversion);}else{c.red = tuple.0 as u8;}if tuple.1 < 0 || tuple.1>255{return Err(IntoColorError::IntConversion);}else{c.green = tuple.1 as u8;}if tuple.2 < 0 || tuple.2>255{return Err(IntoColorError::IntConversion);}else{c.blue = tuple.2 as u8;}Ok(c)}
}// Array implementation
impl TryFrom<[i16; 3]> for Color {type Error = IntoColorError;fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> {let mut c = Color { red: 0, green: 0, blue: 0 };if arr[0] < 0 || arr[0]>255{return Err(IntoColorError::IntConversion);}else{c.red = arr[0] as u8;}if arr[1] < 0 || arr[1]>255 {return Err(IntoColorError::IntConversion);}else{c.green = arr[1] as u8;}if arr[2] < 0 || arr[2]>255{return Err(IntoColorError::IntConversion);}else{c.blue = arr[2] as u8;}Ok(c)}
}// Slice implementation
impl TryFrom<&[i16]> for Color {type Error = IntoColorError;fn try_from(slice: &[i16]) -> Result<Self, Self::Error> {let mut c = Color { red: 0, green: 0, blue: 0 };if slice.len() != 3{return Err(IntoColorError::BadLen);}if slice[0] < 0 || slice[0]>255{return Err(IntoColorError::IntConversion);}else{c.red = slice[0] as u8;}if slice[1] < 0 || slice[1]>255{return Err(IntoColorError::IntConversion);}else{c.green = slice[1] as u8;}if slice[2] < 0 || slice[2]>255{return Err(IntoColorError::IntConversion);}else{c.blue = slice[2] as u8;}Ok(c)}
}fn main() {// Use the `try_from` functionlet c1 = Color::try_from((183, 65, 14));println!("{:?}", c1);// Since TryFrom is implemented for Color, we should be able to use TryIntolet c2: Result<Color, _> = [183, 65, 14].try_into();println!("{:?}", c2);let v = vec![183, 65, 14];// With slice we should use `try_from` functionlet c3 = Color::try_from(&v[..]);println!("{:?}", c3);// or take slice within round brackets and use TryIntolet c4: Result<Color, _> = (&v[..]).try_into();println!("{:?}", c4);
}#[cfg(test)]
mod tests {use super::*;#[test]fn test_tuple_out_of_range_positive() {assert_eq!(Color::try_from((256, 1000, 10000)),Err(IntoColorError::IntConversion));}#[test]fn test_tuple_out_of_range_negative() {assert_eq!(Color::try_from((-1, -10, -256)),Err(IntoColorError::IntConversion));}#[test]fn test_tuple_sum() {assert_eq!(Color::try_from((-1, 255, 255)),Err(IntoColorError::IntConversion));}#[test]fn test_tuple_correct() {let c: Result<Color, _> = (183, 65, 14).try_into();assert!(c.is_ok());assert_eq!(c.unwrap(),Color {red: 183,green: 65,blue: 14});}#[test]fn test_array_out_of_range_positive() {let c: Result<Color, _> = [1000, 10000, 256].try_into();assert_eq!(c, Err(IntoColorError::IntConversion));}#[test]fn test_array_out_of_range_negative() {let c: Result<Color, _> = [-10, -256, -1].try_into();assert_eq!(c, Err(IntoColorError::IntConversion));}#[test]fn test_array_sum() {let c: Result<Color, _> = [-1, 255, 255].try_into();assert_eq!(c, Err(IntoColorError::IntConversion));}#[test]fn test_array_correct() {let c: Result<Color, _> = [183, 65, 14].try_into();assert!(c.is_ok());assert_eq!(c.unwrap(),Color {red: 183,green: 65,blue: 14});}#[test]fn test_slice_out_of_range_positive() {let arr = [10000, 256, 1000];assert_eq!(Color::try_from(&arr[..]),Err(IntoColorError::IntConversion));}#[test]fn test_slice_out_of_range_negative() {let arr = [-256, -1, -10];assert_eq!(Color::try_from(&arr[..]),Err(IntoColorError::IntConversion));}#[test]fn test_slice_sum() {let arr = [-1, 255, 255];assert_eq!(Color::try_from(&arr[..]),Err(IntoColorError::IntConversion));}#[test]fn test_slice_correct() {let v = vec![183, 65, 14];let c: Result<Color, _> = Color::try_from(&v[..]);assert!(c.is_ok());assert_eq!(c.unwrap(),Color {red: 183,green: 65,blue: 14});}#[test]fn test_slice_excess_length() {let v = vec![0, 0, 0, 0];assert_eq!(Color::try_from(&v[..]), Err(IntoColorError::BadLen));}#[test]fn test_slice_insufficient_length() {let v = vec![0, 0];assert_eq!(Color::try_from(&v[..]), Err(IntoColorError::BadLen));}
}

【as_ref_mut.rs】

// Obtain the number of bytes (not characters) in the given argument
// Add the AsRef trait appropriately as a trait bound
fn byte_counter<T:AsRef<str>>(arg: T) -> usize {arg.as_ref().as_bytes().len()
}// Obtain the number of characters (not bytes) in the given argument
// Add the AsRef trait appropriately as a trait bound
fn char_counter<T:AsRef<str>>(arg: T) -> usize {arg.as_ref().chars().count()
}// Squares a number using AsMut. Add the trait bound as is appropriate and
// implement the function body.
fn num_sq<T:AsMut<u32>>(arg: &mut T) {let num = *arg.as_mut() * *arg.as_mut();*arg.as_mut() = num;
}#[cfg(test)]
mod tests {use super::*;#[test]fn different_counts() {let s = "Café au lait";assert_ne!(char_counter(s), byte_counter(s));}#[test]fn same_counts() {let s = "Cafe au lait";assert_eq!(char_counter(s), byte_counter(s));}#[test]fn different_counts_using_string() {let s = String::from("Café au lait");assert_ne!(char_counter(s.clone()), byte_counter(s));}#[test]fn same_counts_using_string() {let s = String::from("Cafe au lait");assert_eq!(char_counter(s.clone()), byte_counter(s));}#[test]fn mult_box() {let mut num: Box<u32> = Box::new(3);num_sq(&mut num);assert_eq!(*num, 9);}
}
												

最新文章

  1. centos7 mysql安装
  2. spring bean作用域_Spring面试知识点,这是我见过最全面的 - 知识铺
  3. Java黑皮书课后题第10章:*10.1(Time类)设计一个名为Time的类。编写一个测试程序,创建两个Time对象(使用new Time()和new Time(555550000))
  4. php 文件 后缀,php如何修改文件后缀名
  5. 打开python环境_windows下切换Python运行环境。
  6. CNNIC报告:中国网民超8亿,人工智能取得突出成果
  7. 两次被简书签约作者拉黑的经历
  8. 通过命令行运行java出现错误: 找不到或无法加载主类 解决办法
  9. 数值分析之奇异值分解(SVD)篇
  10. 路由器手机测试网速的软件,4个实用的无线路由器WiFi检测工具,让你网速又快又稳定...
  11. saas模式的外贸建站比较
  12. 【前端面试题】数据类型-js
  13. ubuntu 安装java运行环境,Ubuntu 安装java环境搭建
  14. 自动化测试全套资料都在这里了,请查收(吐血整理)
  15. 下雨打雷效果(动态)html
  16. 微软账户登入显示空白框,无法创建用户
  17. 小白学 Python(2):基础数据类型(上)
  18. @Autowired浅析
  19. 制定新的计划,走起(r13笔记第1天)
  20. ECharts(3)

热门文章

  1. 【致敬童年】Funcode实现坦克大战
  2. Error: Packagesfrx7 and VCLDB all Contains DBGrids
  3. 如何用SPSS或Excel做中介效应的Sobe检验?
  4. 数学建模:线性规划—投资的收益和风险模型 (Python 求解)
  5. java过滤器是用来干什么的_java过滤器有什么作用
  6. SPSS描述性统计分析
  7. R语言绘制双坐标图直方图与折线的结合
  8. 根据hash值找到bt种子的磁力下载链
  9. pyodbc linux 乱码,python-无法在Linux上安装pyodbc
  10. 手游封包辅助开发教程