Merge pull request #219 from mg-chao/20220116_translate_errors

[rust-exercise] 翻译 error_handling 部分
pull/220/head
Sunface 3 years ago committed by GitHub
commit 644d6ef86d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,9 +1,10 @@
# Error handling
Most errors arent serious enough to require the program to stop entirely.
Sometimes, when a function fails, its for a reason that you can easily interpret and respond to.
For example, if you try to open a file and that operation fails because the file doesnt exist, you might want to create the file instead of terminating the process.
# 错误处理
大多数的错误并没有严重到需要让程序完全停止运行的程度。
有时一个函数执行失败时,你可以很容易地对造成失败的原因进行解释并采取对应措施的。
例如,你正试图打开一个文件,但由于该文件不存在导致了操作失败,这时你可能想创建
该文件而不是直接终止程序。
## Further information
## 更多信息
- [Error Handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html)
- [Generics](https://doc.rust-lang.org/book/ch10-01-syntax.html)

@ -1,18 +1,16 @@
// errors1.rs
// This function refuses to generate text to be printed on a nametag if
// you pass it an empty string. It'd be nicer if it explained what the problem
// was, instead of just sometimes returning `None`. The 2nd test currently
// does not compile or pass, but it illustrates the behavior we would like
// this function to have.
// Execute `rustlings hint errors1` for hints!
// 假使你传给这个函数一个空字符串那么它将拒绝生成一段个性签名nametage
// 如果它能解释拒绝的原因是什么,而不是粗暴返回 `None` 那就更完美了。
// 第 2 个测试目前还没通过并未能编译,但它说明了我们希望这个函数具有的行为。
// 执行 `rustlings hint errors1` 获取提示!
// I AM NOT DONE
pub fn generate_nametag_text(name: String) -> Option<String> {
pub fn generate_nametag_text(name: String) -> Option<String> {// 译:生成个性签名
if name.len() > 0 {
Some(format!("Hi! My name is {}", name))
Some(format!("Hi! My name is {}", name))// 译:"嗨!我的名字是 {}"
} else {
// Empty names aren't allowed.
// 不允许使用空的名字。
None
}
}
@ -21,11 +19,10 @@ pub fn generate_nametag_text(name: String) -> Option<String> {
mod tests {
use super::*;
// This test passes initially if you comment out the 2nd test.
// You'll need to update what this test expects when you change
// the function under test!
// 你可以注释掉第 2 个测试,那么这个测试就能初步通过。
// 当你更改了测试的函数时,也需要修改下测试代码以使测试正确!
#[test]
fn generates_nametag_text_for_a_nonempty_name() {
fn generates_nametag_text_for_a_nonempty_name() {// 译:用一个非空名称生成一段个性签名
assert_eq!(
generate_nametag_text("Beyoncé".into()),
Some("Hi! My name is Beyoncé".into())
@ -33,7 +30,7 @@ mod tests {
}
#[test]
fn explains_why_generating_nametag_text_fails() {
fn explains_why_generating_nametag_text_fails() {// 译:说明为什么个性签名生成失败了
assert_eq!(
generate_nametag_text("".into()),
Err("`name` was empty; it must be nonempty.".into())

@ -1,20 +1,16 @@
// errors2.rs
// Say we're writing a game where you can buy items with tokens. All items cost
// 5 tokens, and whenever you purchase items there is a processing fee of 1
// token. A player of the game will type in how many items they want to buy,
// and the `total_cost` function will calculate the total number of tokens.
// Since the player typed in the quantity, though, we get it as a string-- and
// they might have typed anything, not just numbers!
// Right now, this function isn't handling the error case at all (and isn't
// handling the success case properly either). What we want to do is:
// if we call the `parse` function on a string that is not a number, that
// function will return a `ParseIntError`, and in that case, we want to
// immediately return that error from our function and not try to multiply
// and add.
// There are at least two ways to implement this that are both correct-- but
// one is a lot shorter! Execute `rustlings hint errors2` for hints to both ways.
// 假设我们正在编写一个游戏,你可以用代币购买物品。
// 所有物品的价格都是 5 个代币,每当你购买物品时,都需要 1 个代币的小费。
// 游戏玩家将输入他们想要购买的物品数量,`total_cost` 函数能够计算出所需的代币数量。
// 虽然玩家输入的是数量,但我们得到的却是一个字符串——他们可能输入了任何东西,而不仅仅是数字!
// 目前这个函数没有处理任何错误的情况(也没有处理成功的情况)。
// 我们要做的是:
// 如果我们在非数字的字符串上调用 `parse` 方法,该方法将返回 `ParseIntError`
// 在这种情况下,我们要立刻从函数返回这个错误,而不是继续进行相关计算。
// 至少有两种方法可以做到这点,它们都是正确的——但其中一种简短得多!
// 执行 `rustlings hint errors2` 以获得关于这两种方式的提示。
// I AM NOT DONE
@ -42,6 +38,6 @@ mod tests {
assert_eq!(
total_cost("beep boop").unwrap_err().to_string(),
"invalid digit found in string"
);
);// 译:字符串中包含无效的数字
}
}

@ -1,8 +1,7 @@
// errors3.rs
// This is a program that is trying to use a completed version of the
// `total_cost` function from the previous exercise. It's not working though!
// Why not? What should we do to fix it?
// Execute `rustlings hint errors3` for hints!
// 这是一个试图使用前面练习中 `total_cost` 函数完整版的程序。
// 但出了些问题!为什么不行?我们需要怎样做才能解决问题?
// 执行 `rustlings hint errors3` 获取提示!
// I AM NOT DONE
@ -15,10 +14,10 @@ fn main() {
let cost = total_cost(pretend_user_input)?;
if cost > tokens {
println!("You can't afford that many!");
println!("You can't afford that many!");// 译:你的代币不足以完成支付!
} else {
tokens -= cost;
println!("You now have {} tokens.", tokens);
println!("You now have {} tokens.", tokens);// 译:现在你有 {} 个代币"
}
}

@ -1,5 +1,5 @@
// errors4.rs
// Make this test pass! Execute `rustlings hint errors4` for hints :)
// 通过测试!执行 `rustlings hint errors4` 获取提示 :)
// I AM NOT DONE

@ -1,8 +1,8 @@
// errors5.rs
// This program uses a completed version of the code from errors4.
// It won't compile right now! Why?
// Execute `rustlings hint errors5` for hints!
// 这个程序使用练习 errors4 代码的完整版。
// 它现在不能编译! 为什么呢?
// 执行 `rustlings hint errors5` 获取提示!
// I AM NOT DONE
@ -10,7 +10,7 @@ use std::error;
use std::fmt;
use std::num::ParseIntError;
// TODO: update the return type of `main()` to make this compile.
// TODO:修改 `main()` 的返回类型,以使其通过编译。
fn main() -> Result<(), ParseIntError> {
let pretend_user_input = "42";
let x: i64 = pretend_user_input.parse()?;
@ -18,7 +18,7 @@ fn main() -> Result<(), ParseIntError> {
Ok(())
}
// Don't change anything below this line.
// 不要更改此行以下的任何内容。
#[derive(PartialEq, Debug)]
struct PositiveNonzeroInteger(u64);
@ -39,7 +39,7 @@ impl PositiveNonzeroInteger {
}
}
// This is required so that `CreationError` can implement `error::Error`.
// 以下是必要的,以便 `CreationError` 能够实现 `error::Error` 。
impl fmt::Display for CreationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let description = match *self {

@ -1,18 +1,17 @@
// errors6.rs
// Using catch-all error types like `Box<dyn error::Error>` isn't recommended
// for library code, where callers might want to make decisions based on the
// error content, instead of printing it out or propagating it further. Here,
// we define a custom error type to make it possible for callers to decide
// what to do next when our function returns an error.
// 像 `Box<dyn error::Error>` 这样的万能错误类型并不推荐用于库代码,
// 因为调用者可能想根据错误内容进行相关处理,而不是将其打印出来或进一步传播。
// 在这里,我们自定义了一个错误类型,让调用者有可能去决定当函数返回错误时
// 下一步该怎么做
// Make these tests pass! Execute `rustlings hint errors6` for hints :)
// 通过这些测试!执行 `rustlings hint errors6` 获取提示 :)
// I AM NOT DONE
use std::num::ParseIntError;
// This is a custom error type that we will be using in `parse_pos_nonzero()`.
// 这是一个自定义的错误类型,我们将在 `parse_pos_nonzero()` 中使用。
#[derive(PartialEq, Debug)]
enum ParsePosNonzeroError {
Creation(CreationError),
@ -23,20 +22,19 @@ impl ParsePosNonzeroError {
fn from_creation(err: CreationError) -> ParsePosNonzeroError {
ParsePosNonzeroError::Creation(err)
}
// TODO: add another error conversion function here.
// TODO:在这添加另一个错误转换函数。
}
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.
// TODO改为返回一个恰当的错误而不是在 `parse()` 返回一个错误时 panic
let x: i64 = s.parse().unwrap();
PositiveNonzeroInteger::new(x)
.map_err(ParsePosNonzeroError::from_creation)
}
// Don't change anything below this line.
// 不要更改这一行以下的任何内容。
#[derive(PartialEq, Debug)]
struct PositiveNonzeroInteger(u64);
@ -63,7 +61,7 @@ mod test {
#[test]
fn test_parse_error() {
// We can't construct a ParseIntError, so we have to pattern match.
// 我们不能构造一个 ParseIntError ,所以必须进行模式匹配。
assert!(matches!(
parse_pos_nonzero("not a number"),
Err(ParsePosNonzeroError::ParseInt(_))

@ -433,74 +433,63 @@ name = "errors1"
path = "exercises/error_handling/errors1.rs"
mode = "test"
hint = """
`Err` is one of the variants of `Result`, so what the 2nd test is saying
is that `generate_nametag_text` should return a `Result` instead of an
`Option`.
`Err` `Result` `generate_nametag_text`
`Result` `Option`
To make this change, you'll need to:
- update the return type in the function signature to be a Result<String, String> that
could be the variants `Ok(String)` and `Err(String)`
- change the body of the function to return `Ok(stuff)` where it currently
returns `Some(stuff)`
- change the body of the function to return `Err(error message)` where it
currently returns `None`
- change the first test to expect `Ok(stuff)` where it currently expects
`Some(stuff)`."""
- Result<String, String>便 `Ok(String)` `Err(String)`
- `Some(stuff)` `Ok(stuff)`
- `None` `Err(error message)`
- `Some(stuff)` `Ok(stuff)`"""
[[exercises]]
name = "errors2"
path = "exercises/error_handling/errors2.rs"
mode = "test"
hint = """
One way to handle this is using a `match` statement on
`item_quantity.parse::<i32>()` where the cases are `Ok(something)` and
`Err(something)`. This pattern is very common in Rust, though, so there's
a `?` operator that does pretty much what you would make that match statement
do for you! Take a look at this section of the Error Handling chapter:
`item_quantity.parse::<i32>()` 使 match
`Ok(something)` `Err(something)`
Rust `?`
Error Handling :
https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
and give it a try!"""
"""
[[exercises]]
name = "errors3"
path = "exercises/error_handling/errors3.rs"
mode = "compile"
hint = """
If other functions can return a `Result`, why shouldn't `main`?"""
`Result` `main` """
[[exercises]]
name = "errors4"
path = "exercises/error_handling/errors4.rs"
mode = "test"
hint = """
`PositiveNonzeroInteger::new` is always creating a new instance and returning an `Ok` result.
It should be doing some checking, returning an `Err` result if those checks fail, and only
returning an `Ok` result if those checks determine that everything is... okay :)"""
`PositiveNonzeroInteger::new` `Ok`
`Err` `Ok` :)"""
[[exercises]]
name = "errors5"
path = "exercises/error_handling/errors5.rs"
mode = "compile"
hint = """
Hint: There are two different possible `Result` types produced within
`main()`, which are propagated using `?` operators. How do we declare a
return type from `main()` that allows both?
`main()` `Result` `?`
`main()`
Another hint: under the hood, the `?` operator calls `From::from`
on the error value to convert it to a boxed trait object, a
`Box<dyn error::Error>`, which is polymorphic-- that means that lots of
different kinds of errors can be returned from the same function because
all errors act the same since they all implement the `error::Error` trait.
Check out this section of the book:
`?` `From::from`
`Box<dyn error::Error>`
`error::Error`
https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
This exercise uses some concepts that we won't get to until later in the
course, like `Box` and the `From` trait. It's not important to understand
them in detail right now, but you can read ahead if you like.
使 `Box` `From`
Read more about boxing errors:
boxing errors
https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/boxing_errors.html
Read more about using the `?` operator with boxed errors:
使 `?`
https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/reenter_question_mark.html
"""
@ -509,19 +498,15 @@ name = "errors6"
path = "exercises/error_handling/errors6.rs"
mode = "test"
hint = """
This exercise uses a completed version of `PositiveNonzeroInteger` from
errors4.
使 error 4 `PositiveNonzeroInteger`
Below the line that TODO asks you to change, there is an example of using
the `map_err()` method on a `Result` to transform one type of error into
another. Try using something similar on the `Result` from `parse()`. You
might use the `?` operator to return early from the function, or you might
use a `match` expression, or maybe there's another way!
TODO `Result` 使 `map_err()`
`parse()` `Result` 使西
使 `?` 使 `match`
You can create another function inside `impl ParsePosNonzeroError` to use
with `map_err()`.
`impl ParsePosNonzeroError` `map_err()` 使
Read more about `map_err()` in the `std::result` documentation:
`std::result` `map_err()`
https://doc.rust-lang.org/std/result/enum.Result.html#method.map_err"""
# Generics

Loading…
Cancel
Save