Skip to content
This repository has been archived by the owner on May 5, 2019. It is now read-only.

Commit

Permalink
translate 3.2 panic
Browse files Browse the repository at this point in the history
  • Loading branch information
sunhuachuang committed Aug 21, 2018
1 parent b8e75d4 commit 815ac18
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 270 deletions.
10 changes: 5 additions & 5 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
- [路径清晰化](rust-2018/module-system/path-clarity.md)
- [更加可见的修饰符](rust-2018/module-system/more-visibility-modifiers.md)
- [`use` 进行导入嵌套](rust-2018/module-system/nested-imports-with-use.md)
- [Error handling and panics](rust-2018/error-handling-and-panics/index.md)
- [The `?` operator for easier error handling](rust-2018/error-handling-and-panics/the-question-mark-operator-for-easier-error-handling.md)
- [`?` in `main` and tests](rust-2018/error-handling-and-panics/question-mark-in-main-and-tests.md)
- [Controlling panics with `std::panic`](rust-2018/error-handling-and-panics/controlling-panics-with-std-panic.md)
- [Aborting on panic](rust-2018/error-handling-and-panics/aborting-on-panic.md)
- [错误处理与崩溃](rust-2018/error-handling-and-panics/index.md)
- [`?` 操作符对于早期错误的处理](rust-2018/error-handling-and-panics/the-question-mark-operator-for-easier-error-handling.md)
- [`?` `main` 和 tests中](rust-2018/error-handling-and-panics/question-mark-in-main-and-tests.md)
- [`std::panic` 控制崩溃](rust-2018/error-handling-and-panics/controlling-panics-with-std-panic.md)
- [中止崩溃](rust-2018/error-handling-and-panics/aborting-on-panic.md)
- [Control flow](rust-2018/control-flow/index.md)
- [Loops can `break` with a value](rust-2018/control-flow/loops-can-break-with-a-value.md)
- [`async`/`await` for easier concurrency](rust-2018/control-flow/async-await-for-easier-concurrency.md)
Expand Down
9 changes: 3 additions & 6 deletions src/rust-2018/error-handling-and-panics/aborting-on-panic.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# Aborting on panic
# 中止崩溃

![Minimum Rust version: 1.10](https://img.shields.io/badge/Minimum%20Rust%20Version-1.10-brightgreen.svg)

By default, Rust programs will unwind the stack when a `panic!` happens. If you'd prefer an
immediate abort instead, you can configure this in `Cargo.toml`:
默认情况下,当发生 `panic!` 时,Rust 程序将展开堆栈。如果你更喜欢立即中止,你可以在`Cargo.toml`中配置它:

```toml
[profile.debug]
Expand All @@ -13,6 +12,4 @@ panic = "abort"
panic = "abort"
```

Why might you choose to do this? By removing support for unwinding, you'll
get smaller binaries. You will lose the ability to catch panics. Which choice
is right for you depends on exactly what you're doing.
你为什么选择这样做?通过删除对展开的支持,你将获得更小的二进制文件。你将失去捕捉崩溃的能力。哪种选择取决于你正在做什么。
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# Controlling panics with `std::panic`
# 通过 `std::panic` 处理崩溃

![Minimum Rust version: 1.9](https://img.shields.io/badge/Minimum%20Rust%20Version-1.9-brightgreen.svg)

There is a `std::panic` module, which includes methods for halting the
unwinding process started by a panic:
有一个 `std::panic` 模块,其中包含崩溃,停止和启动的展开过程的方法:

```rust
use std::panic;
Expand All @@ -19,34 +18,23 @@ let result = panic::catch_unwind(|| {
assert!(result.is_err());
```

In general, Rust distinguishes between two ways that an operation can fail:
通常,Rust区分操作失败的两种方式:

- Due to an *expected problem*, like a file not being found.
- Due to an *unexpected problem*, like an index being out of bounds for an array.

Expected problems usually arise from conditions that are outside of your
control; robust code should be prepared for anything its environment might throw
at it. In Rust, expected problems are handled via [the `Result` type][result],
which allows a function to return information about the problem to its caller,
which can then handle the error in a fine-grained way.
- 由于 *预期的问题*,就像找不到文件一样。
- 由于 *意外问题*,就像索引超出数组范围一样。

[result]: http://doc.rust-lang.org/std/result/index.html

Unexpected problems are *bugs*: they arise due to a contract or assertion being
violated. Since they are unexpected, it doesn't make sense to handle them in a
fine-grained way. Instead, Rust employs a "fail fast" approach by *panicking*,
which by default unwinds the stack (running destructors but no other code) of
the thread which discovered the error. Other threads continue running, but will
discover the panic any time they try to communicate with the panicked thread
(whether through channels or shared memory). Panics thus abort execution up to
some "isolation boundary", with code on the other side of the boundary still
able to run, and perhaps to "recover" from the panic in some very coarse-grained
way. A server, for example, does not necessarily need to go down just because of
an assertion failure in one of its threads.

It's also worth noting that programs may choose to *abort* instead of unwind,
and so catching panics may not work. If your code relies on `catch_unwind`, you
should add this to your Cargo.toml:
预期的问题通常来自您无法控制的情况; 应该为其环境可能抛出的任何内容准备健壮的代码。
在Rust中,预期的问题通过 [`Result`类型][result] 来处理,它允许函数将有关问题的信息返回给调用者,然后调用者可以以细粒度的方式处理错误。

意外问题是*错误*:它们是由于合同或断言被违反而产生的。由于它们是意料之外的,因此以细粒度的方式处理它们是没有意义的。
相反,Rust通过*崩溃*采用“快速失败”方法,默认情况下解除发现错误的线程的堆栈(运行析构函数但没有其他代码)。
其他线程继续运行,但每当他们尝试与崩溃线程(无论是通过通道还是共享内存)进行通信时,都会发现崩溃。
因此,崩溃将执行中止到一些“隔离边界”,边界另一侧的代码仍然可以运行,并且可能以某种非常粗粒度的方式从崩溃中“恢复”。
例如,服务器不一定因为其中一个线程中的断言失败而需要关闭。

同样值得注意的是,程序可能会选择*中止*而不是放松,因此捕捉崩溃可能无效。如果你的代码依赖于 `catch_unwind`,你应该将它添加到你的Cargo.toml:

```toml
[profile.debug]
Expand All @@ -56,25 +44,18 @@ panic = "unwind"
panic = "unwind"
```

If any of your users choose to abort, they'll get a compile-time failure.
如果您的任何用户选择中止,他们将遇到编译时失败。

The `catch_unwind` API offers a way to introduce new isolation boundaries
*within a thread*. There are a couple of key motivating examples:
`catch_unwind` API提供了一种在线程中*引入新的隔离边界*的方法。 有几个关键的刺激例子:

* Embedding Rust in other languages
* Abstractions that manage threads
* Test frameworks, because tests may panic and you don't want that to kill the test runner
* 在其他语言中嵌入 Rust
* 管理线程的抽象
* 测试框架,因为测试可能会引起崩溃,你不希望它会杀死测试运行器

For the first case, unwinding across a language boundary is undefined behavior,
and often leads to segfaults in practice. Allowing panics to be caught means
that you can safely expose Rust code via a C API, and translate unwinding into
an error on the C side.
对于第一种情况,跨语言边界展开是未定义的行为,并且经常导致实践中的段错误。
允许捕获崩溃意味着您可以通过 C API 安全地公开 Rust 代码,并将展开转换为C侧的错误。

For the second case, consider a threadpool library. If a thread in the pool
panics, you generally don't want to kill the thread itself, but rather catch the
panic and communicate it to the client of the pool. The `catch_unwind` API is
paired with `resume_unwind`, which can then be used to restart the panicking
process on the client of the pool, where it belongs.
对于第二种情况,请考虑一个线程池库。如果池中的线程发生混乱,您通常不希望杀死线程本身,而是抓住崩溃并将其传递给池的客户端。
`catch_unwind` API 与 `resume_unwind` 配对,然后可以用它来重新启动它所属的池的客户端上的崩溃过程。

In both cases, you're introducing a new isolation boundary within a thread, and
then translating the panic into some other form of error elsewhere.
在这两种情况下,您都在一个线程中引入了一个新的隔离边界,然后将崩溃转换为其他地方的其他形式的错误。
5 changes: 2 additions & 3 deletions src/rust-2018/error-handling-and-panics/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Error handling and Panics
# 错误处理与崩溃

[qop]: the-question-mark-operator-for-easier-error-handling.md

In this chapter of the guide, we discuss a few improvements to error handling
in Rust. The most notable of these is [the introduction of the `?` operator][qop].
在本章节中,我们将讨论 Rust 中一些关于错误处理的改进。 最值得注意的是 [`?` 操作符介绍][qop].
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
# `?` in `main` and tests

# `?``main` 和 tests 中
![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg)

Rust's error handling revolves around returning `Result<T, E>` and using `?`
to propagate errors. For those who write many small programs and, hopefully,
many tests, one common paper cut has been mixing entry points such as `main`
and `#[test]`s with error handling.
Rust的错误处理围绕返回 `Result <T,E>` 并使用 `?` 传播错误。
对于那些编写许多小程序并且希望进行许多测试的人来说,更关注于那些复杂的入口,例如`main``#[test]`中的错误处理。

As an example, you might have tried to write:
举个例子,你将尝试这样写:

```rust,ignore
use std::fs::File;
Expand All @@ -17,9 +14,7 @@ fn main() {
}
```

Since `?` works by propagating the `Result` with an early return to the
enclosing function, the snippet above does not work, and results today
in the following error:
因为 `?` 通过处理 `Result` 并提前返回函数来工作,所以上面的代码不起作用,并且导致以下错误:

```rust,ignore
error[E0277]: the `?` operator can only be used in a function that returns `Result`
Expand All @@ -33,7 +28,7 @@ error[E0277]: the `?` operator can only be used in a function that returns `Resu
= note: required by `std::ops::Try::from_error`
```

To solve this problem in Rust 2015, you might have written something like:
Rust 2015 中,处理这种问题,需要这样:

```rust
// Rust 2015
Expand All @@ -54,12 +49,9 @@ fn main() {
}
```

However, in this case, the `run` function has all the interesting logic and
`main` is just boilerplate. The problem is even worse for `#[test]`s, since
there tend to be a lot more of them.
但是,在这种情况下,`run` 函数具有所有有趣的逻辑,而 `main` 只是样板。 问题更糟糕的是 `#[test]`,因为它们往往会有更多这种情况。

In Rust 2018 you can instead let your `#[test]`s and `main` functions return
a `Result`:
在 Rust 2018 中,你可以使得你的 `#[test]``main` 函数返回一个 `Result`

```rust,no_run
// Rust 2018
Expand All @@ -73,26 +65,22 @@ fn main() -> Result<(), std::io::Error> {
}
```

In this case, if say the file doesn't exist and there is an `Err(err)` somewhere,
then `main` will exit with an error code (not `0`) and print out a `Debug`
representation of `err`.
在这种情况下,如果说文件不存在并且某处有一个 `Err(err)`,那么 `main` 将以错误代码(不是`0`)退出并打印出 `Debug` 表示 `err`

## More details
## 更多的细节

Getting `-> Result<..>` to work in the context of `main` and `#[test]`s is not
magic. It is all backed up by a `Termination` trait which all valid return
types of `main` and testing functions must implement. The trait is defined as:
使 ` - > Result <..>``main``#[test]` 的上下文中工作并不神奇。
它全部由 `Termination` 特征支持,所有有效的返回类型的 `main` 和测试函数必须实现。 特征定义为:

```rust
pub trait Termination {
fn report(self) -> i32;
}
```

When setting up the entry point for your application, the compiler will use this
trait and call `.report()` on the `Result` of the `main` function you have written.
在为应用程序设置入口点时,编译器将使用此特征并在您编写的 `main` 函数的 `Result` 上调用 `.report()`

Two simplified example implementations of this trait for `Result` and `()` are:
`Result` `()` 的这个特性的两个简化示例实现是:

```rust
# #![feature(process_exitcode_placeholder, termination_trait_lib)]
Expand Down Expand Up @@ -122,8 +110,7 @@ impl<E: fmt::Debug> Termination for Result<(), E> {
}
```

As you can see in the case of `()`, a success code is simply returned.
In the case of `Result`, the success case delegates to the implementation for
`()` but prints out an error message and a failure exit code on `Err(..)`.
正如您在 `()` 中看到的那样,只返回成功代码。
`Result` 的情况下,成功的话交给 `()` 来执行,错误的话,交给 `Err(..)`,打印出错误消息并退出代码。

To learn more about the finer details, consult either [the tracking issue](https://github.com/rust-lang/rust/issues/43301) or [the RFC](https://github.com/rust-lang/rfcs/blob/master/text/1937-ques-in-main.md).
要了解有关更细节的信息,请参阅[跟踪问题](https://github.com/rust-lang/rust/issues/43301) 或者 [the RFC](https://github.com/rust-lang/rfcs/blob/master/text/1937-ques-in-main.md).

0 comments on commit 815ac18

Please sign in to comment.