前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Rustlings练习-vec、String、hashmap、error_handling

Rustlings练习-vec、String、hashmap、error_handling

作者头像
用户7267083
发布2022-12-08 15:10:35
7960
发布2022-12-08 15:10:35
举报
文章被收录于专栏:sukuna的博客

Rustlings练习-vec、String、hashmap、error_handling

于2022年10月20日2022年10月20日由Sukuna发布

9-1

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

代码语言:javascript
复制
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方法对里面的元素统一使用一个函数进行更改

代码语言:javascript
复制
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

改错

代码语言:javascript
复制
// 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

代码语言:javascript
复制
// 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,也是把每个单词分开来,加一个判断而已.

代码语言:javascript
复制
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的?

代码语言:javascript
复制
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());
}

答案就是这个:

代码语言:javascript
复制
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就好了.

代码语言:javascript
复制
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进行插入

代码语言:javascript
复制
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的值.

代码语言:javascript
复制
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都是字符串,负责传回一个字符串.

代码语言:javascript
复制
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就要直接返回.

代码语言:javascript
复制
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,就会自动向上面传递问题.

代码语言:javascript
复制
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函数进行处理.

代码语言:javascript
复制
    let cost = match total_cost(pretend_user_input){
        Ok(a) => a,
        Err(E) => {
            panic!("G");
        }
    };

12-4

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

代码语言:javascript
复制
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类型了!

代码语言:javascript
复制
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类型中有两种不同的枚举值.对于不同的枚举值代表两种不同的错误.

代码语言:javascript
复制
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)
}

上面就是错误的迭代,或者说嵌套…弄清楚错误是可以嵌套的,这道题就很好写了.

代码语言:javascript
复制
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)
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年10月20日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Rustlings练习-vec、String、hashmap、error_handling
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档