pull/564/head
sunface 3 years ago
commit e6a208747f

@ -283,3 +283,38 @@ impl<T> Clone for Container<T> {
你以为你之前凝视的是深渊吗?不,你凝视的只是深渊的大门。 `mem::transmute_copy<T, U>` 才是真正的深渊,它比之前的还要更加危险和不安全。它从 `T` 类型中拷贝出 `U` 类型所需的字节数,然后转换成 `U``mem::transmute` 尚有大小检查,能保证两个数据的内存大小一致,现在这哥们干脆连这个也丢了,只不过 `U` 的尺寸若是比 `T` 大,会是一个未定义行为。 你以为你之前凝视的是深渊吗?不,你凝视的只是深渊的大门。 `mem::transmute_copy<T, U>` 才是真正的深渊,它比之前的还要更加危险和不安全。它从 `T` 类型中拷贝出 `U` 类型所需的字节数,然后转换成 `U``mem::transmute` 尚有大小检查,能保证两个数据的内存大小一致,现在这哥们干脆连这个也丢了,只不过 `U` 的尺寸若是比 `T` 大,会是一个未定义行为。
当然,你也可以通过原生指针转换和 `unions` (todo!)获得所有的这些功能,但是你将无法获得任何编译提示或者检查。原生指针转换和 `unions` 也不是魔法,无法逃避上面说的规则。 当然,你也可以通过原生指针转换和 `unions` (todo!)获得所有的这些功能,但是你将无法获得任何编译提示或者检查。原生指针转换和 `unions` 也不是魔法,无法逃避上面说的规则。
`transmute` 虽然危险,但作为一本工具书,知识当然要全面,下面列举两个有用的 `transmute` 应用场景 :)。
- 将原生指针变成函数指针:
```rust
fn foo() -> i32 {
0
}
let pointer = foo as *const ();
let function = unsafe {
// 将原生指针转换为函数指针
std::mem::transmute::<*const (), fn() -> i32>(pointer)
};
assert_eq!(function(), 0);
```
- 延长生命周期,或者缩短一个静态生命周期寿命:
```rust
struct R<'a>(&'a i32);
// 将 'b 生命周期延长至 'static 生命周期
unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> {
std::mem::transmute::<R<'b>, R<'static>>(r)
}
// 将 'static 生命周期缩短至 'c 生命周期
unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) -> &'b mut R<'c> {
std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r)
}
```
以上例子非常先进!但是是非常不安全的 Rust 行为!

@ -172,7 +172,7 @@ let home: IpAddr = "127.0.0.1".parse().unwrap();
当调用 `panic!` 宏时,它会 当调用 `panic!` 宏时,它会
1. 格式化 `panic` 信息,然后使用该信息作为参数,调用 `std::panic::panic_any()` 函数 1. 格式化 `panic` 信息,然后使用该信息作为参数,调用 `std::panic::panic_any()` 函数
2. `panic_any` 会检查应用是否使用了 `panic hook`,如果使用了,该 `hook` 函数就会被调用(`hook` 是一个钩子函数,是外部代码设置的,用于在 `panic` 触发时,执行外部代码所需的功能) 2. `panic_any` 会检查应用是否使用了 [`panic hook`](https://doc.rust-lang.org/std/panic/fn.set_hook.html),如果使用了,该 `hook` 函数就会被调用(`hook` 是一个钩子函数,是外部代码设置的,用于在 `panic` 触发时,执行外部代码所需的功能)
3. 当 `hook` 函数返回后,当前的线程就开始进行栈展开:从 `panic_any` 开始,如果寄存器或者栈因为某些原因信息错乱了,那很可能该展开会发生异常,最终线程会直接停止,展开也无法继续进行 3. 当 `hook` 函数返回后,当前的线程就开始进行栈展开:从 `panic_any` 开始,如果寄存器或者栈因为某些原因信息错乱了,那很可能该展开会发生异常,最终线程会直接停止,展开也无法继续进行
4. 展开的过程是一帧一帧的去回溯整个栈,每个帧的数据都会随之被丢弃,但是在展开过程中,你可能会遇到被用户标记为 `catching` 的帧(通过 `std::panic::catch_unwind()` 函数标记),此时用户提供的 `catch` 函数会被调用,展开也随之停止:当然,如果 `catch` 选择在内部调用 `std::panic::resume_unwind()` 函数,则展开还会继续。 4. 展开的过程是一帧一帧的去回溯整个栈,每个帧的数据都会随之被丢弃,但是在展开过程中,你可能会遇到被用户标记为 `catching` 的帧(通过 `std::panic::catch_unwind()` 函数标记),此时用户提供的 `catch` 函数会被调用,展开也随之停止:当然,如果 `catch` 选择在内部调用 `std::panic::resume_unwind()` 函数,则展开还会继续。

@ -84,9 +84,12 @@
## F ## F
| 名称 | 关键字 | 简介 | | 名称 | 关键字 | 简介 |
| ---- | ------ | ------------- | | -------- | -------- | -------------------------- |
| [浮点数] | 数值类型 | `f32` <br> `f64`(默认类型) |
| F | KWF | FIntroduction | | F | KWF | FIntroduction |
[浮点数]: https://course.rs/basic/base-type/numbers.html#浮点类型
[back](#head) [back](#head)
## G ## G
@ -193,9 +196,14 @@
## S ## S
| 名称 | 关键字 | 简介 | | 名称 | 关键字 | 简介 |
| ---- | ------ | ------------- | | ------------ | -------- | ------------------------------------------------------------------------------------------------------ |
| [整数] | 数值类型 | 有符号整数,`i8`,`i16`,`i32`,`i64`,`i128`,`isize`<br>无符号整数,`u8`,`u16`,`u32`,`u64`,`u128`,`usize` |
| [整形字面量] | 进制书写 | 十进制 `98_222`<br>十六进制 `0xff`<br>八进制 `0o77`<br>二进制 `0b1111_0000`<br>字节(仅限于`u8`) `b'A'` |
| S | KWS | SIntroduction | | S | KWS | SIntroduction |
[整数]: https://course.rs/basic/base-type/numbers.html#整数类型
[整形字面量]: https://course.rs/basic/base-type/numbers.html#整数类型
[back](#head) [back](#head)
## T ## T
@ -233,9 +241,12 @@
## X ## X
| 名称 | 关键字 | 简介 | | 名称 | 关键字 | 简介 |
| ---- | ------ | ------------- | | ------ | ------ | ---------------------------------------------------------------------------------- |
| [序列] | Range | 生成连续的数值<br> 只允许用于数字或字符类型<br> `..` 右半开区间 <br>`..=` 闭合区间 |
| X | KWX | XIntroduction | | X | KWX | XIntroduction |
[序列]: https://course.rs/basic/base-type/numbers.html#序列range
[back](#head) [back](#head)
## Y ## Y

Loading…
Cancel
Save