Post

🧩 rustlings quiz

quiz2 题目

rustlings的题目好像会变。现在做的这个quiz2的题目是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// 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!

// I AM NOT DONE

pub enum Command {
    Uppercase,
    Trim,
    Append(usize),
}

mod my_module {
    use super::Command;

    // TODO: Complete the function signature!
    pub fn transformer(input: ???) -> ??? {
        // TODO: Complete the output declaration!
        let mut output: ??? = vec![];
        for (string, command) in input.iter() {
            // TODO: Complete the function body. You can do it!
        }
        output
    }
}

#[cfg(test)]
mod tests {
    // TODO: What do we need to import to have `transformer` in scope?
    use ???;
    use super::Command;

    #[test]
    fn it_works() {
        let output = transformer(vec![
            ("hello".into(), Command::Uppercase),
            (" all roads lead to rome! ".into(), Command::Trim),
            ("foo".into(), Command::Append(1)),
            ("bar".into(), Command::Append(5)),
        ]);
        assert_eq!(output[0], "HELLO");
        assert_eq!(output[1], "all roads lead to rome!");
        assert_eq!(output[2], "foobar");
        assert_eq!(output[3], "barbarbarbarbarbar");
    }
}

主要就是transformer方法里面,要做就是对传进来的 参数 进行操作, 参数是 一个Vector,里面的元素是一个元组类型

对于每一个元组,对第一个元素做相应的操作,这个操作由第二个元素给定。 第二个元素这里是一个枚举类型,列举出了三种操作

  1. 变成大写
  2. 去掉空白
  3. 追加bar字符串,根据枚举对象关联的值,是几,就追加几个bar

input类型和返回值类型

由测试案例得知

` pub fn transformer(input: Vec<String,Command>) -> Vec {`

assert_eq!(output[0],"HELLO")这里跟取出来的对比不是 &str 吗?

是的,但是其实这里会做一件事就是 deref,这里是自动的

返回 Vec<&str> ???

可以这样,但是有点麻烦, 一方面是值的问题,另一方面那就涉及到生命周期了

我现在还没学到那么深,先粗略的了解一下,

因为这里给 Vec 里面塞了 &str类型,其实就是引用,而这个值肯定来子函数内部产生,因为Rust的特性,这个值在函数结束后肯定会释放了。

如果还想使用的话,要么就通过所有权转移出去,要么就需要是 static 的(不在堆上)

我感觉现阶段就先到这,还是先用 Vec<String>就行了

input.iter(c)

其实

for i in a = for i in a.into_iter()

for i in &a = for i in a.iter()

for i in &mut a = for i in a.iter_mut()

对于 input.iter(),在for and iterators 中介绍

iter - This borrows each element of the collection through each iteration.

所以如果我们 input 定义的是 Vec<(String,Command)>

那么在这里 for (string: &String,command: &Command) in input.iter() 就应该是这样

这里我是这样写的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    pub fn transformer(input: Vec<(String, Command)>) -> Vec<String> {
        // TODO: Complete the output declaration!
        let mut output: Vec<String> = vec![];
        for (string, command) in input.iter() {
            // TODO: Complete the function body. You can do it!
            match command {
                &Command::Uppercase => output.push(string.to_uppercase().into()),
                &Command::Trim => output.push(string.trim().into()),
                &Command::Append(count) => {
                    let mut string = string.clone();
                    for _ in 0..count as i32 {
                        string = string + "bar";
                    }
                    output.push(string.into());
                }
            }
        }
        output
    }

to_uppercase,trim

因为string是 &String 类型,其实在这里也可以理解为借用。所以直接用这个方法也可以

但是to_uppercase() 返回的是String类型

trim()返回的是&str类型

这里统统用一个 into() 交给编译去处理好了,我目前对他的理解是,他会根据上下文自动转化的

match command or match *command

都可以,但是对应不同的用法

1
2
3
4
5
6
7
8
9
10
11
12
            match command {
                Command::Uppercase => output.push(string.to_uppercase().into()),
                Command::Trim => output.push(string.trim().into()),
                Command::Append(count) => {
                    let mut string = string.clone();
                    for _ in 0..*count as i32 {
                        string = string + "bar";
                    }
                    output.push(string.into());
                }
            }

注意 *count as i32的 * 号

1
2
3
4
5
6
7
8
9
10
11
            match *command {
                Command::Uppercase => output.push(string.to_uppercase().into()),
                Command::Trim => output.push(string.trim().into()),
                Command::Append(count) => {
                    let mut string = string.clone();
                    for _ in 0..count as i32 {
                        string = string + "bar";
                    }
                    output.push(string.into());
                }
            }

注意 match *command

1
2
3
4
5
6
7
8
9
10
11
            match command {
                &Command::Uppercase => output.push(string.to_uppercase().into()),
                &Command::Trim => output.push(string.trim().into()),
                &Command::Append(count) => {
                    let mut string = string.clone();
                    for _ in 0..*count as i32 {
                        string = string + "bar";
                    }
                    output.push(string.into());
                }
            }

注意 每一个分支前面的 &

count as i32

因为 Command::Append(count) => { 我这里解构出来的count其实是 usize 类型,枚举中定义的

然后 0..count这种形式需要 count是一个 integer

use module

1
2
3
4
5
#[cfg(test)]
mod tests {
    // TODO: What do we need to import to have `transformer` in scope?
    use ???;
    use super::Command;

这里就是需要用 use 来创建一个 快捷键, 看下面直接用的是 transformer,所以引入进来就可以了

1
2
3
4
5
#[cfg(test)]
mod tests {
    // TODO: What do we need to import to have `transformer` in scope?
    use super::my_module::transformer;
    use super::Command;

其他人的写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
mod my_module {
    use super::Command;

    // TODO: Complete the function signature!
    pub fn transformer(input: Vec<(String, Command)>) -> Vec<String> {
        // TODO: Complete the output declaration!
        let mut output: Vec<String> = vec![];
        for (string, command) in input.iter() {
            // TODO: Complete the function body. You can do it!
            let s = match command {
                Command::Uppercase => string.to_uppercase(),
                Command::Trim => string.trim().into(),
                Command::Append(i) => string.to_owned() + &"bar".repeat(*i),
            };
            output.push(s);
        }
        output
    }
}

to_owned方法

之所以要用这个方法是因为 string是 &String类型

字符串的 + 其实是需要 String + &str -> String

repeat()方法

库函数不熟悉,学到了。

This post is licensed under CC BY 4.0 by the author.