9-1

用vec宏声明一个新的Vector.这道题负责了解Vec!和直接声明的区别.

fn array_and_vec() -> ([i32; 4], Vec<i32>) {
    let a = [10, 20, 30, 40]; // a plain array
    let v = vec!(10,20,30,40);
    (a, v)
}

用直接声明是一个[i32,n]的类型,用vec!()宏可以声明一个Vec<T>类型的变量.

9-2

这一题需要我们把Vec里面的所有元素*2.

我们有两种版本,一个是使用迭代器,依次迭代解引用更改即可.还可以使用map方法对里面的元素统一使用一个函数进行更改

fn vec_loop(mut v: Vec<i32>) -> Vec<i32> {
    for i in v.iter_mut() {
        *i = *i * 2;
    }
    // At this point, `v` should be equal to [4, 8, 12, 16, 20].
    v
}

fn vec_map(v: &Vec<i32>) -> Vec<i32> {
    v.iter().map(|num| {
        // TODO: Do the same thing as above - but instead of mutating the
        // Vec, you can just return the new number!
         num * 2
    }).collect()
}

10-1

改错

// strings1.rs
// Make me compile without changing the function signature!
// Execute `rustlings hint strings1` or use the `hint` watch subcommand for a hint.

// I AM NOT DONE

fn main() {
    let answer = current_favorite_color();
    println!("My current favorite color is {}", answer);
}

fn current_favorite_color() -> String {
    "blue"
}

“blue”不是String类型的,它是一个常量字符串,两种改法:改成let赋值模式、或者改成返回&‘static 类型就好.

10-2

改错,也是一样的,传进来的是一个String类型的元素,但是函数的签名却是&str

// strings2.rs
// Make me compile without changing the function signature!
// Execute `rustlings hint strings2` or use the `hint` watch subcommand for a hint.


fn main() {
    let word = String::from("green"); // Try not changing this line :)
    if is_a_color_word(word) {
        println!("That is a color word I know!");
    } else {
        println!("That is not a color word I know.");
    }
}

fn is_a_color_word(attempt: &str) -> bool {
    attempt == "green" || attempt == "blue" || attempt == "red"
}

所以说把函数签名的&str改成string就好.

10-3

写3个很简单的小函数.

一个是在后面加一个world,就是使用push_str函数在后面加上即可.

一个是去掉前面和后面的空格.就把每个单词分开来,然后组装在一起.

一个是把所有的cars换成balloons,也是把每个单词分开来,加一个判断而已.

fn trim_me(input: &str) -> String {
    // TODO: Remove whitespace from both ends of a string!
    let s = input.to_string();
    let mut ne = String::new();
    for word in s.split_whitespace(){
        ne.push_str(word);
        ne.push_str(" ");
    }
    ne.pop();
    ne
}

fn compose_me(input: &str) -> String {
    // TODO: Add " world!" to the string! There's multiple ways to do this!
    let mut s = input.to_string();
    s.push_str(" world!");
    s
}

fn replace_me(input: &str) -> String {
    // TODO: Replace "cars" in the string with "balloons"!
    let s = input.to_string();
    let mut ne = String::new();
    for word in s.split_whitespace(){
        if word == "cars"{
            ne.push_str("balloons");
        }
        else{
            ne.push_str(word);
        }
        ne.push_str(" ");
    }
    ne.pop();
    ne
}

10-4

判断是String还是&str的?

fn string_slice(arg: &str) {
    println!("{}", arg);
}
fn string(arg: String) {
    println!("{}", arg);
}

fn main() {
    ???("blue");
    ???("red".to_string());
    ???(String::from("hi"));
    ???("rust is fun!".to_owned());
    ???("nice weather".into());
    ???(format!("Interpolation {}", "Station"));
    ???(&String::from("abc")[0..1]);
    ???("  hello there ".trim());
    ???("Happy Monday!".to_string().replace("Mon", "Tues"));
    ???("mY sHiFt KeY iS sTiCkY".to_lowercase());
}

答案就是这个:

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

11-1

这一题需要我们声明一个空的HashMap,然后插入若干个key-value对.插入就调用insert就好了.

use std::collections::HashMap;

fn fruit_basket() -> HashMap<String, u32> {
    let mut basket = HashMap::new();// TODO: declare your hash map here.

    // Two bananas are already given for you :)
    // TODO: Put more fruits in your basket here.
    basket.insert(String::from("banana"), 2);
    basket.insert(String::from("Apple"), 2);
    basket.insert(String::from("Orange"), 2);

    basket
}

11-2

这一题需要我们完成哈希表的判断插入,当这个表没有这个元素的时候才进行插入操作,在书本上说过可以用enrty和or_insert进行插入

fn fruit_basket(basket: &mut HashMap<Fruit, u32>) {
    let fruit_kinds = vec![
        Fruit::Apple,
        Fruit::Banana,
        Fruit::Mango,
        Fruit::Lychee,
        Fruit::Pineapple,
    ];

    for fruit in fruit_kinds {
        // TODO: Put new fruits if not already present. Note that you
        // are not allowed to put any type of fruit that's already
        // present!
        let k = basket.entry(fruit).or_insert(1);
    }
}

11-3

这一题需要我们统计一个球队输球和赢球的数量,需要用到or_insert,用到or_insert的返回值,这个返回值是一个引用,可以改变value的值.

use std::collections::HashMap;

// A structure to store team name and its goal details.
struct Team {
    name: String,
    goals_scored: u8,
    goals_conceded: u8,
}

fn build_scores_table(results: String) -> HashMap<String, Team> {
    // The name of the team is the key and its associated struct is the value.
    let mut scores: HashMap<String, Team> = HashMap::new();

    for r in results.lines() {
        let v: Vec<&str> = r.split(',').collect();
        let team_1_name = v[0].to_string();
        let team_1_score: u8 = v[2].parse().unwrap();
        let team_2_name = v[1].to_string();
        let team_2_score: u8 = v[3].parse().unwrap();
        // TODO: Populate the scores table with details extracted from the
        // current line. Keep in mind that goals scored by team_1
        // will be number of goals conceded from team_2, and similarly
        // goals scored by team_2 will be the number of goals conceded by
        let g = scores.entry(team_1_name.to_string()).or_insert(Team{name:team_1_name,goals_scored:0,goals_conceded:0});
        (*g).goals_scored = (*g).goals_scored + team_1_score;
        (*g).goals_conceded = (*g).goals_conceded + team_2_score;
        let f = scores.entry(team_2_name.to_string()).or_insert(Team{name:team_2_name,goals_scored:0,goals_conceded:0});
        (*f).goals_scored = (*f).goals_scored + team_2_score;
        (*f).goals_conceded = (*f).goals_conceded + team_1_score;
    }
    scores
}

12-1

这一题单纯用来了解Result的特征,Result<T,E>是一个枚举类型,其中Ok的类型是T,Err的类型是E,如果一个函数会返回Result在不同情况下会返回Ok或者Err两种元素.

这一题的T和E都是字符串,负责传回一个字符串.

pub fn generate_nametag_text(name: String) -> Result<String,String> {
    if name.is_empty() {
        // Empty names aren't allowed.
        Err("`name` was empty; it must be nonempty.".into())
    } else {
        Ok(format!("Hi! My name is {}", name))
    }
}

12-2

这一题我们需要了解最基本的错误的处理方式,第一种处理方式就是match一个Result值,Result值有两种枚举的可能,一个是Ok(T),一个是Err(E),分步处理即可.如果是Err就要直接返回.

use std::num::ParseIntError;

pub fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
    let processing_fee = 1;
    let cost_per_item = 5;
    let qty = match item_quantity.parse::<i32>(){
        Ok(T) => T,
        Err(E) => {
            return Err(E);
        },
    };

    Ok(qty * cost_per_item + processing_fee)
}

12-3

这一题主要是了解Result的?用法.

如果加上了?这个符号在一个可以返回Result<T,E>的函数调用后面,这个符号可以完成这个任务:

如果是Ok,这个表达式的值就是Ok的值,如果是Err,就会自动向上面传递问题.

use std::num::ParseIntError;

fn main() {
    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);
    }
}

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>()?;

    Ok(qty * cost_per_item + processing_fee)
}

这个代码里面就是有一个?,item_quantity.parse::<i32>()?没问题就返回这个i32,如果有问题就向上面抛出异常.

上层需要处理这个异常.一种改法是让main也返回Result类型,还有一种就是把?去掉加上match函数进行处理.

    let cost = match total_cost(pretend_user_input){
        Ok(a) => a,
        Err(E) => {
            panic!("G");
        }
    };

12-4

这一题和上一题一样,教我们怎么返回Ok或者抛出异常.

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

12-5

main函数能返回Result类型:

将???改为error::Error,指动态匹配错误的类型.完成了fmt::Display就是error::Error类型了!

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 ???>> {
    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 {}

12-6

这一个就是在Err(E)中加了点手脚,就是Err(E)中E的类型也是一个Err类型.

这里是创建了一个新的Err类型,Err类型中有两种不同的枚举值.对于不同的枚举值代表两种不同的错误.

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)
    }
    fn from_parseint(err: ParseIntError) -> ParsePosNonzeroError{
        ParsePosNonzeroError::ParseInt(err)
    }
    // TODO: add another error conversion function here.
    // fn from_parseint...
}

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: i64 = match s.parse(){
        Ok(T) => T,
        Err(E) => {
            return Err(ParsePosNonzeroError::from_parseint(E));
        },
    };
    PositiveNonzeroInteger::new(x)
        .map_err(ParsePosNonzeroError::from_creation)
}

分类: 杂项

0 条评论

发表评论

Avatar placeholder

您的电子邮箱地址不会被公开。 必填项已用*标注

隐藏