diff --git a/contents/advance/macro.md b/contents/advance/macro.md index ff4020ce..3187b73a 100644 --- a/contents/advance/macro.md +++ b/contents/advance/macro.md @@ -158,7 +158,7 @@ let v = { 由于绝大多数 Rust 开发者都是宏的用户而不是编写者,因此在这里我们不会对 `macro_rules` 进行更深入的学习,如果大家感兴趣,可以看看这本书 [ “The Little Book of Rust Macros”](https://veykril.github.io/tlborm/)。 ## 用过程宏为属性标记生成代码 -第二种常用的宏就是[*过程宏*](https://doc.rust-lang.org/reference/procedural-macros.html) ( *procedural macros* ),从形式上来看,过程宏跟函数较为相像,但过程宏是使用源代码作为输入参数,基于代码进行一系列操作后,再输出一段全新的代码。**注意,过程宏输出的代码并不会替换之前的代码,这一点与声明宏有很大的不同!** +第二种常用的宏就是[*过程宏*](https://doc.rust-lang.org/reference/procedural-macros.html) ( *procedural macros* ),从形式上来看,过程宏跟函数较为相像,但过程宏是使用源代码作为输入参数,基于代码进行一系列操作后,再输出一段全新的代码。**注意,过程宏中的derive宏输出的代码并不会替换之前的代码,这一点与声明宏有很大的不同!** 至于前文提到的过程宏的三种类型(自定义 `derive`、属性宏、函数宏),它们的工作方式都是类似的。 @@ -462,4 +462,4 @@ Rust 中的宏主要分为两大类:声明宏和过程宏。 虽然 Rust 中的宏很强大,但是它并不应该成为我们的常规武器,原因是它会影响 Rust 代码的可读性和可维护性,我相信没有几个人愿意去维护别人写的宏 :) -因此,大家应该熟悉宏的使用场景,但是不要滥用,当你真的需要时,再回来查看本章了解实现细节,这才是最完美的使用方式。 \ No newline at end of file +因此,大家应该熟悉宏的使用场景,但是不要滥用,当你真的需要时,再回来查看本章了解实现细节,这才是最完美的使用方式。 diff --git a/contents/confonding/slice.md b/contents/confonding/slice.md index c0deb940..8769f1db 100644 --- a/contents/confonding/slice.md +++ b/contents/confonding/slice.md @@ -26,6 +26,12 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t 总之,我们可以总结出一个结论:**在 Rust 中,所有的切片都是动态类型,它们都无法直接被使用**。 +### 为什么切片是动态类型 +很简单,切片就是一个未知长度的数组,前面已经讲过, 未知长度的类型是不能分配在栈上的, 所以你不能用 `let s: [T] = ...` 的形式来声明一个栈上的变量。 那么有什么办法来使用数组呢? +1. 固定长度数组, 声明时带上长度: `let a: [i8;4] = [1,2,3,4];` +2. 对于不固定长度的, 使用切片引用,切片引用类似于`trait object`,也是一个胖指针, 包含了切片的起始位置和长度,这样一来因为切片引用的大小是固定的(一个起始位置,一个长度,当然大小固定啦),也就能在栈上分配了。 + + 那么问题来了,该如何使用切片呢? ## 切片引用 @@ -46,7 +52,7 @@ let s3: &[i32] = &arr[1..3]; ## 总结 我们常常说使用切片,实际上我们在用的是切片的引用,我们也在频繁说使用字符串,实际上我们在使用的也是字符串切片的引用。 -总之,切片在 Rust 中是动态类型 DST,是无法被我们直接使用的,而我们在使用的都是且切片的引用。 +总之,切片在 Rust 中是动态类型 DST,是无法被我们直接使用的,而我们在使用的都是切片的引用。 | 切片 | 切片引用| | --- | --- |