diff --git a/book/contents/basic/converse.md b/book/contents/basic/converse.md index 73a01166..4ef4a04d 100644 --- a/book/contents/basic/converse.md +++ b/book/contents/basic/converse.md @@ -163,7 +163,7 @@ error[E0277]: the trait bound `&mut i32: Trait` is not satisfied 再进一步,我们使用[完全限定语法](https://course.rs/basic/trait/advance-trait.html#完全限定语法)来进行准确的函数调用: 1. 首先,编译器检查它是否可以直接调用 `T::foo(value)`,称之为**值方法调用** -2. 如果上一步调用无法完成(例如方法类型错误或者特征没有针对 `Self` 进行实现,上文提到过特征不能进行强制转换),那么编译器会尝试增加自动引用,以为着编译器会尝试以下调用: `<&T>::foo(value)` 和 `<&mut T>::foo(value)`,称之为**引用方法调用** +2. 如果上一步调用无法完成(例如方法类型错误或者特征没有针对 `Self` 进行实现,上文提到过特征不能进行强制转换),那么编译器会尝试增加自动引用,例如会尝试以下调用: `<&T>::foo(value)` 和 `<&mut T>::foo(value)`,称之为**引用方法调用** 3. 若上面两个方法依然不工作,编译器会试着解引用 `T` ,然后再进行尝试。这里使用了 `Deref` 特征 —— 若 `T: Deref` (`T` 可以被解引用为 `U`),那么编译器会使用 `U` 类型进行尝试,称之为**解引用方法调用** 4. 若 `T` 不能被解引用,且 `T` 是一个定长类型(在编译器类型长度是已知的),那么编译器也会尝试将 `T` 从定长类型转为不定长类型,例如将 `[i32; 2]` 转为 `[i32]` 5. 若还是不行,那...没有那了,最后编译器大喊一声:汝欺我甚,不干了! @@ -189,7 +189,7 @@ fn do_stuff(value: &T) { let cloned = value.clone(); } ``` -上面例子中 `cloned` 的类型时什么?首先编译器检查能不能进行**值方法调用**, `value` 的类型是 `&T`,同时 `clone` 方法的签名也是 `&T` : `fn clone(&T) -> T`,因此可以进行值方法调用,再加上编译器知道了 `T` 实现了 `Clone`,因此 `cloned` 的类型是 `T`。 +上面例子中 `cloned` 的类型是什么?首先编译器检查能不能进行**值方法调用**, `value` 的类型是 `&T`,同时 `clone` 方法的签名也是 `&T` : `fn clone(&T) -> T`,因此可以进行值方法调用,再加上编译器知道了 `T` 实现了 `Clone`,因此 `cloned` 的类型是 `T`。 如果 `T: Clone` 的特征约束被移除呢? ```rust diff --git a/book/contents/basic/result-error/panic.md b/book/contents/basic/result-error/panic.md index 79d7a997..7bd47e92 100644 --- a/book/contents/basic/result-error/panic.md +++ b/book/contents/basic/result-error/panic.md @@ -88,7 +88,7 @@ note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose bac panic = 'abort' ``` -## 线程`panic`后,程序会否终止? +## 线程`panic`后,程序是否会终止? 长话短说,如果是 `main` 线程,则程序会终止,如果是其它子线程,该线程会终止,但是不会影响 `main` 线程。因此,尽量不要在 `main` 线程中做太多任务,将这些任务交由子线程去做,就算子线程 `panic` 也不会导致整个程序的结束。 具体解析见[panic原理剖析](#panic原理剖析) @@ -136,7 +136,7 @@ let home: IpAddr = "127.0.0.1".parse().unwrap(); - 后续代码的运行会受到显著影响 - 内存安全的问题 -当错误预期会出现时,返回一个错误较为合适,例如解析器接收到格式错误的数据,HTTP请求接收到错误的参数甚至该请求内的任何错误(不会导致整个程序有问题,只影响该此请求)。 **因为错误是可预期的,因此也是可以处理的**。 +当错误预期会出现时,返回一个错误较为合适,例如解析器接收到格式错误的数据,HTTP请求接收到错误的参数甚至该请求内的任何错误(不会导致整个程序有问题,只影响该次请求)。 **因为错误是可预期的,因此也是可以处理的**。 当启动时某个流程发生了错误,对后续代码的运行造成了影响,那么就应该使用 `panic`,而不是处理错误后继续运行,当然你可以通过重试的方式来继续。 @@ -155,5 +155,5 @@ let home: IpAddr = "127.0.0.1".parse().unwrap(); 还有一种情况,在展开过程中,如果展开本身 `panic` 了,那展开线程会终止,展开也随之停止。 -一旦线程展开被终止或者完成,最终的输出结果是取决于哪个线程 `panic:对于 `main` 线程,操作系统提供的终止功能 `core::intrinsics::abort()` 会被调用,最终结束当前的 `panic` 进程;如果是其它子线程,那么子线程就会简单的终止,同时信息会在稍后通过 `std::thread::join()` 进行收集。 +一旦线程展开被终止或者完成,最终的输出结果是取决于哪个线程 `panic`:对于 `main` 线程,操作系统提供的终止功能 `core::intrinsics::abort()` 会被调用,最终结束当前的 `panic` 进程;如果是其它子线程,那么子线程就会简单的终止,同时信息会在稍后通过 `std::thread::join()` 进行收集。