diff --git a/assets/rustlings-zh/Cargo.lock b/assets/rustlings-zh/Cargo.lock index e536d1b7..7c71b46a 100644 --- a/assets/rustlings-zh/Cargo.lock +++ b/assets/rustlings-zh/Cargo.lock @@ -524,9 +524,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ "aho-corasick", "memchr", diff --git a/assets/rustlings-zh/Cargo.toml b/assets/rustlings-zh/Cargo.toml index 983d1bf5..226c0111 100644 --- a/assets/rustlings-zh/Cargo.toml +++ b/assets/rustlings-zh/Cargo.toml @@ -10,7 +10,7 @@ indicatif = "0.10.3" console = "0.7.7" notify = "4.0.15" toml = "0.4.10" -regex = "1.1.6" +regex = "1.5.5" serde = {version = "1.0.10", features = ["derive"]} [[bin]] diff --git a/src/advance/concurrency-with-threads/sync2.md b/src/advance/concurrency-with-threads/sync2.md index c715b29b..b1822971 100644 --- a/src/advance/concurrency-with-threads/sync2.md +++ b/src/advance/concurrency-with-threads/sync2.md @@ -175,7 +175,7 @@ X = 2; } - **Relaxed**, 这是最宽松的规则,它对编译器和 CPU 不做任何限制,可以乱序 - **Release 释放**,设定内存屏障(Memory barrier),保证它之前的操作永远在它之前,但是它后面的操作可能被重排到它前面 - **Acquire 获取**, 设定内存屏障,保证在它之后的访问永远在它之后,但是它之前的操作却有可能被重排到它后面,往往和`Release`在不同线程中联合使用 -- **AcqRel**, **Acquire**和**Release**的结合,同时拥有它们俩提供的保证。比如你要对一个 `atomic` 自增 1,同时希望该操作之前和之后的读取或写入操作不会被重新排序 +- **AcqRel**, 是 *Acquire* 和 *Release* 的结合,同时拥有它们俩提供的保证。比如你要对一个 `atomic` 自增 1,同时希望该操作之前和之后的读取或写入操作不会被重新排序 - **SeqCst 顺序一致性**, `SeqCst`就像是`AcqRel`的加强版,它不管原子操作是属于读取还是写入的操作,只要某个线程有用到`SeqCst`的原子操作,线程中该`SeqCst`操作前的数据操作绝对不会被重新排在该`SeqCst`操作之后,且该`SeqCst`操作后的数据操作也绝对不会被重新排在`SeqCst`操作前。 这些规则由于是系统提供的,因此其它语言提供的相应规则也大同小异,大家如果不明白可以看看其它语言的相关解释。 diff --git a/src/advance/functional-programing/iterator.md b/src/advance/functional-programing/iterator.md index af8f0663..00ca73cc 100644 --- a/src/advance/functional-programing/iterator.md +++ b/src/advance/functional-programing/iterator.md @@ -406,9 +406,9 @@ assert_eq!(18, sum); 其中 `zip`,`map`,`filter` 是迭代器适配器: -- `zip` 把两个迭代器合并成一个迭代器,新迭代器中,每个元素都是一个元组,由之前两个迭代器的元素组成。例如将**形如** `[1, 2, 3]` 和 `[4, 5, 6]` 的迭代器合并后,新的迭代器形如 `[(1, 4),(2, 5),(3, 6)]` -- `map` 是将迭代器中的值经过映射后,转换成新的值 -- `filter` 对迭代器中的元素进行过滤,若闭包返回 `true` 则保留元素,反之剔除 +- `zip` 把两个迭代器合并成一个迭代器,新迭代器中,每个元素都是一个元组,由之前两个迭代器的元素组成。例如将**形如** `[1, 2, 3, 4, 5]` 和 `[2, 3, 4, 5]` 的迭代器合并后,新的迭代器形如 `[(1, 2),(2, 3),(3, 4),(4, 5)]` +- `map` 是将迭代器中的值经过映射后,转换成新的值[2, 6, 12, 20] +- `filter` 对迭代器中的元素进行过滤,若闭包返回 `true` 则保留元素[6, 12],反之剔除 而 `sum` 是消费者适配器,对迭代器中的所有元素求和,最终返回一个 `u32` 值 `18`。 diff --git a/src/async-rust/tokio/getting-startted.md b/src/async-rust/tokio/getting-startted.md index 36a5757c..22a74520 100644 --- a/src/async-rust/tokio/getting-startted.md +++ b/src/async-rust/tokio/getting-startted.md @@ -141,7 +141,7 @@ pub async fn connect(addr: T) -> Result { 在上例中,`redis` 的连接函数 `connect` 实现如上,它看上去很像是一个同步函数,但是 `async fn` 出卖了它。 `async fn` 异步函数并不会直接返回值,而是返回一个 `Future`,顾名思义,该 `Future` 会在未来某个时间点被执行,然后最终获取到真实的返回值 `Result`。 -> async/await 的原理就算大家不理解,也不妨碍使用 `tokio` 写出能用的服务,但是如果想要更深入的用好,强烈建议认真读下本书的 [`async/await` 异步编程章节](https://course.rs/async/intro.html),你会对 Rust 的异步编程有一个全新且深刻的认识。 +> async/await 的原理就算大家不理解,也不妨碍使用 `tokio` 写出能用的服务,但是如果想要更深入的用好,强烈建议认真读下本书的 [`async/await` 异步编程章节](https://course.rs/async-rust/async/intro.html),你会对 Rust 的异步编程有一个全新且深刻的认识。 由于 `async` 会返回一个 `Future`,因此我们还需要配合使用 `.await` 来让该 `Future` 运行起来,最终获得返回值: diff --git a/src/first-try/slowly-downloading.md b/src/first-try/slowly-downloading.md index def7437c..d4430a9f 100644 --- a/src/first-try/slowly-downloading.md +++ b/src/first-try/slowly-downloading.md @@ -28,7 +28,7 @@ export https_proxy=http://127.0.0.1:7890 http_proxy=http://127.0.0.1:7890 all_pr #### 增加新的镜像地址 -**首先是在 `crates.io` 之外添加新的注册服务**,在 `$HOME/.cargo/config.toml` 中添加以下内容: +**首先是在 `crates.io` 之外添加新的注册服务**,在 `$HOME/.cargo/config.toml` (如果文件不存在则手动创建一个)中添加以下内容: ```toml [registries] @@ -49,6 +49,8 @@ time = { registry = "ustc" } 而第二种方式,则不需要修改 `Cargo.toml` 文件,**因为它是直接使用新注册服务来替代默认的 `crates.io`**。 +在 `$HOME/.cargo/config.toml` 添加以下内容: + ```toml [source.crates-io] replace-with = 'ustc' diff --git a/src/index-list.md b/src/index-list.md index 1843af8b..6a855205 100644 --- a/src/index-list.md +++ b/src/index-list.md @@ -39,7 +39,7 @@ | [@] | 变量绑定 | 为一个字段绑定另外一个变量 | | `_` : 1. [忽略变量] 2. [模式匹配] | 忽略 | 1. 忽略该值或者类型,否则编译器会给你一个 `变量未使用的` 的警告
2. 模式匹配通配符 | | ['a: 'b] | 生命周期约束 | 用来说明两个生命周期的长短 | -| [{:?}] {:#?} | 打印结构体信息 | 使用 `#[derive(Debug)]` 派生实现 `Debug` 特征 | +| [{:?}] {:#?} | 打印结构体信息 | 使用 `#[derive(Debug)]` 派生实现 `Debug` 特征,另见 [格式化输出] | | [::] | 关联函数 | 定义在 `impl` 中且没有 `self` 的函数 | | | | @@ -55,6 +55,7 @@ [忽略变量]: https://course.rs/basic/variable.html#使用下划线开头忽略未使用的变量 [模式匹配]: https://course.rs/basic/match-pattern/match-if-let.html#_-通配符 [::]: https://course.rs/basic/method.html#关联函数 +[格式化输出]: https://course.rs/basic/formatted-output.html#-与- [back](#head) @@ -98,16 +99,17 @@ ## C -| 名称 | 关键字 | 简介 | -| ------------------ | -------- | ----------------------------------------------------------------------------------- | -| [char 字符] | 字符类型 | 使用 `''` 表示,所有的 Unicode 值 | -| [const 常量] | constant | `const MAX_POINTS: u32 = 100_000;` | -| [const 泛型] | 泛型 | `const N: usize` 针对值的泛型,适合处理数组长度的问题 | -| [const 泛型表达式] | 泛型 | | -| [Copy 拷贝] | 浅拷贝 | 任何基本类型的组合可以 `Copy`,不需要分配内存或某种形式资源的类型是可以 `Copy` 的。 | -| [continue] | 循环控制 | 跳过当前当次的循环,开始下次的循环 | -| [Clone 克隆] | 深拷贝 | 需要复制堆上的数据时,可以使用 `.clone()` 方法 | -| | KWC | | +| 名称 | 关键字 | 简介 | +| ------------------ | -------- | ---------------------------------------------------------------------------------------------------------------- | +| [char 字符] | 字符类型 | 使用 `''` 表示,所有的 Unicode 值 | +| [const 常量] | constant | `const MAX_POINTS: u32 = 100_000;` | +| [const 泛型] | 泛型 | `const N: usize` 针对值的泛型,适合处理数组长度的问题 | +| [const 泛型表达式] | 泛型 | | +| [Copy 拷贝] | 浅拷贝 | 任何基本类型的组合可以 `Copy`,不需要分配内存或某种形式资源的类型是可以 `Copy` 的。 | +| [continue] | 循环控制 | 跳过当前当次的循环,开始下次的循环 | +| [Clone 克隆] | 深拷贝 | 需要复制堆上的数据时,可以使用 `.clone()` 方法 | +| [Closure] | 闭包 | 闭包是一种匿名函数,它可以赋值给变量也可以作为参数传递给其它函数,不同于函数的是,它允许[捕获调用者作用域中的值] | +| | KWC | | [char 字符]: https://course.rs/basic/base-type/char-bool.html#字符类型char [const 常量]: https://course.rs/basic/variable.html#变量和常量之间的差异 @@ -116,6 +118,8 @@ [continue]: https://course.rs/basic/flow-control.html#continue [const 泛型]: https://course.rs/basic/trait/generic.html#const-泛型rust-151-版本引入的重要特性 [const 泛型表达式]: https://course.rs/basic/trait/generic.html#const-泛型表达式 +[closure]: https://course.rs/advance/functional-programing/closure.html +[捕获调用者作用域中的值]: https://course.rs/advance/functional-programing/closure.html#捕获作用域中的值 [back](#head) @@ -154,6 +158,8 @@ | [for 循环] | 循环控制 | `for item in &collection {}` | | ['fn' 函数] | | 函数名和变量名使用 `蛇形命名法(snake case)`
函数的位置可以随便放
每个函数参数都需要标注类型 | | [调用同名的方法] | | 1. 默认调用类型上的方法
`Struct.function(receiver_if_method, next_arg, ...);`
2. 显式调用特征上的方法
`Trait::function(receiver_if_method, next_arg, ...);`
3. [完全限定语法]
`::function(receiver_if_method, next_arg, ...);` | +| [三种 Fn 特征] | 闭包 | 闭包[捕获变量]有三种途径,恰好对应函数参数的三种传入方式:转移所有权、可变借用、不可变借用 | +| [三种 Fn 的关系] | 闭包 | | | | KWF | | [浮点数]: https://course.rs/basic/base-type/numbers.html#浮点类型 @@ -161,6 +167,9 @@ ['fn' 函数]: https://course.rs/basic/base-type/function.html [调用同名的方法]: https://course.rs/basic/trait/advance-trait.html#调用同名的方法 [完全限定语法]: https://course.rs/basic/trait/advance-trait.html#完全限定语法 +[三种 fn 特征]: https://course.rs/advance/functional-programing/closure.html#三种-fn-特征 +[捕获变量]: https://course.rs/advance/functional-programing/closure.html#捕获作用域中的值 +[三种 fn 的关系]: https://course.rs/advance/functional-programing/closure.html#三种-fn-的关系 [back](#head) @@ -300,10 +309,12 @@ | --------------------- | ------------ | -------------------------------------------------------------------- | | [panic! 不可恢复错误] | 不可恢复错误 | 程序会打印出一个错误信息,展开报错点往前的函数调用堆栈,最后退出程序 | | [panic 原理剖析] | 不可恢复错误 | | +| [println!] | 格式化参数 | 对输出内容格式有更多要求 | | | KWP | | [panic! 不可恢复错误]: https://course.rs/basic/result-error/panic.html#panic-与不可恢复错误 [panic 原理剖析]: https://course.rs/basic/result-error/panic.html#panic-原理剖析 +[println!]: https://course.rs/basic/formatted-output.html#格式化参数 [back](#head) @@ -343,6 +354,13 @@ | [struct 结构体] | 结构体 | 通过关键字 `struct` 定义
一个清晰明确的结构体 `名称`
几个有名字的结构体 `字段`
通过 `.` 访问字段 | | [self &self &mut self] | Method 方法 | `self` 指代类型的实例 | | [Self 与 self] | | `self` 指代当前的实例对象,`Self` 指代特征或者方法类型的别名 | +| [生命周期标注语法] | 生命周期 | `&'a i32` | +| [生命周期消除] | 生命周期 | | +| [生命周期消除规则补充] | 生命周期 | | +| [函数中的生命周期] | 生命周期 | | +| [结构体中的生命周期] | 生命周期 | | +| [方法中的生命周期] | 生命周期 | | +| [静态生命周期] | 生命周期 | `&'static` 拥有该生命周期的引用可以和整个程序活得一样久,另见 [&'static 和 T: 'static] | | | KWS | | [所有权与堆栈]: https://course.rs/basic/ownership/ownership.html#所有权与堆栈 @@ -354,6 +372,14 @@ [struct 结构体]: https://course.rs/basic/compound-type/struct.html [self &self &mut self]: https://course.rs/basic/method.html#selfself-和-mut-self [self 与 self]: https://course.rs/basic/trait/trait-object#self-与-self +[生命周期标注语法]: https://course.rs/advance/lifetime/basic.html#生命周期标注语法 +[生命周期消除]: https://course.rs/advance/lifetime/basic.html#生命周期消除 +[生命周期消除规则补充]: https://course.rs/advance/lifetime/advance.html#生命周期消除规则补充 +[函数中的生命周期]: https://course.rs/advance/lifetime/basic.html#函数中的生命周期 +[结构体中的生命周期]: https://course.rs/advance/lifetime/basic.html#结构体中的生命周期 +[方法中的生命周期]: https://course.rs/advance/lifetime/basic.html#方法中的生命周期 +[静态生命周期]: https://course.rs/advance/lifetime/basic.html#静态生命周期 +[&'static 和 t: 'static]: https://course.rs/advance/lifetime/static.html [back](#head) diff --git a/src/profiling/performance/intro.md b/src/profiling/performance/intro.md index f9cb9ea5..9bdb73dd 100644 --- a/src/profiling/performance/intro.md +++ b/src/profiling/performance/intro.md @@ -11,4 +11,7 @@ https://zhuanlan.zhihu.com/p/191655266 https://www.reddit.com/r/rust/comments/s793x7/force_4byte_memory_alignment/ ## riggrep 为啥这么快 -https://www.reddit.com/r/rust/comments/sr02aj/what_makes_ripgrep_so_fast/ \ No newline at end of file +https://www.reddit.com/r/rust/comments/sr02aj/what_makes_ripgrep_so_fast/ + +## 测试堆性能 +https://flakm.github.io/posts/heap_allocation/ \ No newline at end of file diff --git a/src/rust-weekly.md b/src/rust-weekly.md index 058b90fe..99a5de37 100644 --- a/src/rust-weekly.md +++ b/src/rust-weekly.md @@ -5,59 +5,54 @@ Rust语言周刊精选全世界过去一周的优秀文章、新闻、开源项 > RustCn:https://hirust.cn, 公众号: Rust语言中文网 -# 「Rust 语言周刊」 第 14 期 · 2022-05-29 -Rust语言周刊精选全世界过去一周的优秀文章、新闻、开源项目和语言动态。 - -本周刊由 RustCn 社区倾情打造,其中, `[Zh]` 标识的中文资料由 Rust 翻译计划提供,并且原始的 Markdown 文档已[全部开源](https://github.com/rustlang-cn/rustt),欢迎大家阅读和订阅。 - -> RustCn:https://hirust.cn, 公众号: Rust语言中文网 - - -
题图: 将 Ruby 的编译器移植到 Rust 上
+# 「Rust 语言周刊」 第 15 期 · 2022-06-10 -#### Rust 项目 + +
题图: Rust 好难啊
-1、[IntelliJ 的 Rust 插件发布新版本](https://blog.jetbrains.com/rust/2022/05/19/what-s-new-in-intellij-rust-for-2022-1/) -Vscode 的 Rust 插件 `rust-analyzer` 已经相当牛了,但是跟 IntelliJ 依然有一定的差距。告诉大家一个小秘密,ra 之前的的核心作者其实也是 IntelliJ Rust 插件的核心开发,当然,现在 ra 在合并到官方组织后,跟以前又有所不同了。 +## 精选文章 -#### 精选文章 +1、[简单的 Rust 面试问题](https://flakm.github.io/posts/rust_interview_questions/) -1、[为了开发一个操作系统,我学习了 Rust 并写下 10 万行代码](https://www.bunniestudios.com/blog/?p=6375) +当年(2015)我搜索 Go 语言工作时有多绝望,你现在搜索 Rust 工作就有多绝望,再优秀的语言,要在行业里流行开来,总需要时间的沉淀,不管如何,Rust 现在正在走在一条正确的快行道上。 -对于作者所在的公司来说,他们希望能清晰地掌控 OS 的每一个细节,虽说 linux 是开源的,但是它实在太大了,而其他的开源系统或多或少页无法满足他们的需求,因此需要重新手撸一个 OS。那么,在这个时间点,对于这种需求,除了 Rust 之外,还有更好的选择吗?显然没有。 +因此,无论是面试官还是面试者,提前储备一些 Rust 的面试题,都是不错的选择。 -2、[从零构建一个云数据库:我们为何从 C++ 迁移到 Rust](https://singularity-data.com/blog/building-a-cloud-database-from-scratch-why-we-moved-from-cpp-to-rust/) +2、[来自强类型的诅咒](https://fasterthanli.me/articles/the-curse-of-strong-typing) -就我个人而言,真的很羡慕国外的技术人生存环境,你能想象,国内创业公司在开发 7 个月后删除了所有的 C++ 代码,然后从零开始,使用 Rust 从头开始吗?作者所在的公司就是这样一(yi)股(duo)清(qi)流(pa)。 +我骑着马儿,穿过了雪山,来到了草原,遇到了美丽的...错误?!大家写 Rust 有没有这种感觉,从题目可以看出,作者是绝对有这种感觉的,特别是在他的 Boss 宣称:从今以后,我们的一切都要使用 Rust 后... -3、[修复 Rust 中的内存泄漏问题](https://onesignal.com/blog/solving-memory-leaks-in-rust/) +3、[测量 Rust 中的堆内存分配](https://flakm.github.io/posts/heap_allocation/) -OneSignal 是一个消息服务公司,在之前将其中的一些核心服务[迁移到了 Rust 上](https://onesignal.com/blog/rust-at-onesignal/),在此过程中,他们遇到并解决了不少问题,其中一个就是内存泄漏。 +如果问程序员,为何要节省内存,他会说这是技术的体现;如果问老板,为何要节省内存,他会说这是因为穷。总是,在节省硬件成本这件事上,大家的目标出奇的一致。那么现在的问题就是:该如何衡量应用的内存使用情况? -这篇文章干货多多,非常值得深入阅读! +4、[Arc 和 Mutex](https://itsallaboutthebit.com/arc-mutex/) -4、[Rust 中的崩溃处理](https://jake-shadle.github.io/crash-reporting/) +这篇文章讲解了一个很有趣的点:`Arc` 为何要求其包裹的类型实现 `Sync` 特征,值得一看! -不知道大家学过 Erlang 没,这门语言不仅是现代化并发编程的引路者,还是崩溃哲学的提倡者:错误不应该被隐藏,而是直接抛出来,任其崩溃,若有需要,自动重启任务协程即可(通过 gen_supervisor 统一管理)。 +5、[使用 Github Actions 让 Rust 构建提速 30 倍](https://ectobit.com/blog/speed-up-github-actions-rust-pipelines/) -当然,这种特立独行的方式并不适合于所有的语言和开发者,因此 Rust 中并没有内置这套崩溃自动处理系统,而是需要我们根据自己的需求来手动处理,这篇文章就介绍了一些不错的崩溃处理方式。 +Rust 什么都好,就是编译太慢了,特别是你同时写 Go 和 Rust 时,那种对比体验更是明显。原因在于,在编译过程中,为了安全性和性能 Rust 会检查很多很多东西,何况 Rust 提供的语言特性也远比 Go 要更加丰富。 -5、[从 BonsaiDb 的性能问题引发的文件同步性能探究](https://bonsaidb.io/blog/durable-writes/) +当然,这个过程是可以提速的,例如在 `Cargo.toml` 中设置编译优化选项,再比如本文中的构建缓存。 -数据库是非常复杂的领域,作者本来想要同时搞定中上层数据库服务和底层数据存储服务,但是在遇到了一系列问题后,现在不禁怀疑,自己实现底层数据存储服务是否是一个正确的抉择。 -6、[优化 Rust 二进制文件的大小](https://kerkour.com/optimize-rust-binary-size) +6、[Rust 好难啊](https://hirrolot.github.io/posts/rust-is-hard-or-the-misery-of-mainstream-programming.html) -这篇文章很短,只介绍了优化大小的一些途径( 其实不是很全 ),并没有对此进行深入展开,我个人其实并不想把文章列到周刊中,但是鉴于本期的内容素材并不多,只能向现实屈服了 :( +Rust 之所以给很多人难学的印象,很重要的一点就在于:某些其它语言很轻松就能处理的问题,在 Rust 中,你需要兼具美貌、智慧与勇气,才能搞定。 -7、[使用 Github Actions 来测试和构建你的 Rust 应用](https://kerkour.com/rust-github-actions-ci-cd) +大家可能以为这篇文章是一个新手写的,其实不然,作者已经浸淫 Rust 数年,还在某次大会上分享过 Rust,但是他依然会遇到一些意料之外的棘手错误,一起来看看吧。 -这篇文章的推荐程度同上,如果大家想要全面了解 Github Actions,可以看看 Rust 语言圣经中的[这篇章节](https://course.rs/test/ci.html)。 +7、[爆发和挑战并存](https://thestack.technology/rust-language-explosive-growth-challenges-rust-governance/) +在过去 24 个月中,Rust 开发者的数量增加了 3 倍,可以说从 Rust 基金会成立后,Rust 一直在爆发式增长,但是其所面临的挑战也越来越大。 +8、[使用 Rust 来爬取网页](https://www.scrapingbee.com/blog/web-scraping-rust/) +想从某些网站获取信息,一般有两个途径:首先就是调用网站提供的 API,这也是最安全、最合法的方式(特别是国内!),例如 Github 就提供了异常丰富的 API;其次,就是使用爬虫来爬取到网页后,再对内容进行解析,以提取出有用的信息。 +9、[Video][使用 Rust 来编写 WGPU 程序](https://www.youtube.com/playlist?list=PL_UrKDEhALdJS0VrLPn7dqC5A4W1vCAUT) @@ -65,6 +60,7 @@ OneSignal 是一个消息服务公司,在之前将其中的一些核心服务[ 目前所有的周刊都按照 `年/月/日期` 的方式归纳在 [docs](./docs) 目录下,大家可以按需查看。 +- [第 14 期](./docs/2022/5月/29.md) - [第 13 期](./docs/2022/5月/22.md) - [第 12 期](./docs/2022/5月/16.md) - [第 11 期](./docs/2022/5月/07.md) diff --git a/src/too-many-lists/ok-stack/iter.md b/src/too-many-lists/ok-stack/iter.md index 17aa6d4a..627c7730 100644 --- a/src/too-many-lists/ok-stack/iter.md +++ b/src/too-many-lists/ok-stack/iter.md @@ -194,7 +194,7 @@ pub struct Iter<'a, T> { // 这里无需生命周期,因为 List 没有使用生命周期的关联项 impl List { - // 这里我们为 `iter` 生命一个生命周期 'a , 此时 `&self` 需要至少和 `Iter` 活得一样久 + // 这里我们为 `iter` 声明一个生命周期 'a , 此时 `&self` 需要至少和 `Iter` 活得一样久 pub fn iter<'a>(&'a self) -> Iter<'a, T> { Iter { next: self.head.map(|node| &node) } }