Post

🧩 rustlings conversions

from_into

这个题就是要去完成 impl From<&str> for Person {} 方法

我自己的解法,就是很不rust

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
impl From<&str> for Person{
	fn from(s: &str) -> Person{
		let fields: Vec<&str> = s.split(',').collect();
		if fields.len() == 2{
			let name = fields.[0];
			let age = fields.[1];

			if let Ok(age) = age.parse::<usize>(){
				if name.len!=0{
					return Person{name:name,age:age};
				}
			}
		}

		Person::default()
	}

}

然后我看了其他人的写法,用了 split_oncematch 风格更rust一点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
impl From<&str> for Person {
    fn from(s: &str) -> Person {
        let (name, age) = match s.split_once(',') {
            Some((name, age)) => (name.trim(), age.trim()),
            None => return Person::default(),
        };
        if let Ok(age) = age.parse::<usize>() {
            if name.len() > 0 {
                return Person {
                    name: name.to_string(),
                    age: age,
                };
            }
        };
        Person::default()
    }
}

from_str

感觉自己对match的用法还不够理解深入,光能识别,但用不起来,问题处在哪呢?

这是我写的解法

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
impl FromStr for Person {
    type Err = ParsePersonError;
    fn from_str(s: &str) -> Result<Person, Self::Err> {
        if s.is_empty() {
            return Err(ParsePersonError::Empty);
        };
        let fields: Vec<&str> = s.split(',').collect();
        if fields.len() != 2 {
            return Err(ParsePersonError::BadLen);
        } else {
            let (name, age) = (fields[0], fields[1]);
            if name.len() == 0 {
                return Err(ParsePersonError::NoName);
            }

            match age.parse::<usize>() {
                Ok(age) => {
                    return Ok(Person {
                        name: name.to_string(),
                        age: age,
                    });
                }
                Err(e) => return Err(ParsePersonError::ParseInt(e)),
            }
        }
    }
}

if,else 一大堆

看了别人的写法,最主要就是match的用法和 Error Propagation

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
impl FromStr for Person {
    type Err = ParsePersonError;
    fn from_str(s: &str) -> Result<Person, Self::Err> {
        if s.is_empty() {
            return Err(ParsePersonError::Empty);
        }

        let fields: Vec<&str> = s.split(',').collect();

        let (name, age) = match &fields[..] {
            [name, age] => (
                name.to_string(),
                age.parse::<usize>().map_err(ParsePersonError::ParseInt)?,
            ),
            _ => return Err(ParsePersonError::BadLen),
        };
        if name.is_empty() {
            return Err(ParsePersonError::NoName);
        }
        Ok(Person {
            name: name,
            age: age,
        })
    }
}

为什么 ParsePersonError::ParseInt 可以当作参数传给 map_err 呢?

因为在这里 ParseInt 其实是一个 tuple variant constructor,也就是是一个构造器,所以他是一个Fn,自然也是一个 FnOnce

然后这里match的其实是变量名

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