Rust入门方法——边刷Leetcode边学Rust

学习一门新语言首先要熟悉这门语言的语法,通过做一些简单的Leetcode题来熟悉新语法,也许能够达到事半功倍的效果吧。

可因为一些众所周知的原因,在一天之中的大部分时间都不太适合直接在Leetcode的网站上刷题。不过,好在可以先把题目和代码模版复制到VS Code等编辑器中,在那里编写代码解决题目,待调试测试过后,再找合适的时机把代码复制到Leetcode的网站上并提交。

例如,在学习Go语言时,我经常这样在VS Code中练习新语法:

// /path/to/leetcode/1.go
package main


import "fmt"


// 1. 两数之和
// 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出和为目标值 target 的那两个整数,并返回它们的数组下标。
// ...


func twoSum(nums []int, target int) []int {
  // ...
}

为了验证是否正确,只需要在main函数中编写一些测试用例:

func main() {
	// if expect != actual {
	// 	...
	// 	fmt.Printf("❌expect != actual, expect: %v, actual: %v\n", tc.expect, actual)
	// } else {
  //		fmt.Printf("✅expect == actual\n")
	// }
}

最后,只要再go run 1.go一下,就可以开始测试。

go run 1.go             
✅expect == actual
✅expect == actual

main()到处开花的笨办法

我用这个方法既学习了Go语言的语法,还顺带刷了不少Leetcode题。于是,在学习Rust时,就打算继续使用这个方法,但开头并不是那么顺利。

通过网上的一些教程,我知道先要通过cargo命令创建一个项目,如cargo new rust-leetcode。本打算每道题一个.rs文件,并在main.rs中调用相应的单元测试函数,最后调用cargo run命令进行测试,例如:

.
├── Cargo.lock
├── Cargo.toml
├── src
│   ├── 1.rs
│   └── main.rs
|...
// 1.rs
impl Solution {
    pub fn two_sum(nums: Vec<i32>, target: i32) -> Vec<i32> {
			// ...
    }
}


fn test_two_sum() {
    // ...
}
// main.rs
fn main() {
    test_two_sum();
}

但执行cargo run后,却报错了,

error[E0425]: cannot find function `test_two_sum` in this scope
 --> src/main.rs:2:5
  |
2 |     test_two_sum();
  |     ^^^^^^^^^^^^ not found in this scope


For more information about this error, try `rustc --explain E0425`.
error: could not compile `rust-lc` (bin "rust-lc") due to previous error

我当时并不知道如何解决这个错误,最终只得放弃使用cargo,把fn main()移动到每道题的源文件中(如1.rs),然后通过rustc xxx.rs && ./xxx进行测试,

$ fgrep 'fn main' -rn .
./1079.rs:53:fn main() {
./1925.rs:46:fn main() {
./main.rs:2:fn main() {
...


$ tree .
.
├── 1079
├── 1079.rs
├── 1925
├── 1925.rs
...

肥蟹书教会我如何组织项目内的代码

好在这种main()到处开花的笨办法没持续多长时间,就迎来了称为“肥蟹书”的《Rust 程序设计(第2版)》。而且刚好第8章就讲到了如何组织项目内的代码以及Rust内置的文档测试框架

a299fdb1a9474685bacb9b0c243ab172.png

肥蟹书的8.2节提到,“模块是关于项目内代码组织的“,那是不是把每道Leetcode题看作是一个模块就可以了?经过实验,答案是肯定的,而且Rust还支持3种组织模块的方法

  • 模块位于自己的文件中

  • 模块位于自己的带有mod.rs的目录中

  • 模块在自己的文件中,并带有包含子模块的补充目录

这3种方法说起来还挺绕嘴的,但好在书中给了一个具体示例,

fern_sim/
├── Cargo.toml
└── src/
		├── main.rs
		├── spores.rs
		└── plant_structures/
				├── mod.rs
				├── leaves.rs
				├── roots.rs
				├── stems/
				│ ├── phloem.rs
				│ └── xylem.rs
				└── stems.rs

我们可以对照着这个树形结构去正文中寻找每种方法的描述。下面是从书中摘录出来的内容

第一种方法:

spores 模块保存在一个单独的名为 spores.rs 的文件中 …… 当 Rust 看到 mod spore; 时,会同时检查 spores.rs 和 spores/mod.rs……

第二种方法:

我们声明了 plant_structures 模块:

pub mod plant_structures;

这会导致 Rust 加载 plant_structures/mod.rs,该文件声明了 3 个子模块:

// 在plant_structures/mod.rs中
pub mod roots;
pub mod stems;
pub mod leaves;

这 3 个模块的内容存储在 leaves.rs、 roots.rs 和 stems.rs 这 3 个单独的文件中,与 mod.rs 一 样位于 plant_structures 目录下。

第三种方法:

也可以使用同名的文件和目录来组成模块。如果 stems(茎)需要包含称为 xylem(木质 部)和 phloem(韧皮部)的模块,那么可以选择将 stems 保留在 plant_structures/stems.rs 中 并添加一个 stems 目录…… 然后,在 stems.rs 中,我们声明了两个新的子模块:

// 在plant_structures/stems.rs中
pub mod xylem;
pub mod phloem;

虽然可能还是无法用一两句话说清楚这三种方法,但很容易“照猫画虎”,把刷Leetcode题的代码组织起来了,我还特意使用不同的方法来组织linked_list模块和tree模块。

.
├── Cargo.lock
├── Cargo.toml
├── src
│   ├── lc1281.rs
│   ├── lc1572.rs
...
│   ├── lc833.rs
│   └── lc918.rs
│   ├── lib.rs
│   ├── linked_list
│   │   ├── lc21.rs
│   │   ├── lc83.rs
│   │   ├── mod.rs
│   │   └── offer06.rs
│   ├── tree
│   └── tree.rs

文档测试

为了避免频繁打开Leetcode的网页,提交代码以验证结果,最好是先在VS Code中进行单元测试。虽然肥蟹书的8.6节提到了:

Rust 中内置了一个简单的单元测试框架,测试是标有 #[test] 属性的普通函数:

#[test]
fn math_works() {
	let x: i32 = 1;
	assert!(x.is_positive());
	assert_eq!(x + 1, 2);
}

cargo test 会运行项目中的所有测试:

$ cargo test
Compiling math_test v0.1.0 (file:///.../math_test)
Running target/release/math_test-e31ed91ae51ebf22
running 1 test
test math_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

这似乎已经满足验证代码是否正确的基本需求了,但只要再往下读两小节,就会发现书中介绍了一种更适合刷题时使用的测试方法——文档测试。

0858e65eadcd627cfe7d5329447dc269.png

如上图所示,只要把代码写入到文档型注释中(以 3 个斜杠开头的注释),VS Code就会出现一个“Run Doctest”的按钮。只需要点击这个按钮,就可以开始运行单元测试。

于是在VS Code中用Leetcode练习Rust语法就变得非常方便了:

  1. 复制Leetcode的题目要求和函数模版

  2. 编写代码

  3. 在文档型注释中插入测试用例

  4. 点击“Run Doctest”按钮

  5. 复制写好的代码到Leetcode的页面并提交

现在,可以充分利用每天的宝贵时间安心学习Rust了。

哦对了,值得一提的是,肥蟹书的前两位作者是Mozilla创始团员,在系统编程领域已经有 20 多年的经验:

aff5c788f2f090ed9cb51497d7b7a317.png

而译者是25年老码农雪狼(汪志成),他在这本书从翻译到出版的过程中,前前后后对稿子修订了7遍,每一遍都耗费了巨大的心血。

a6f27337be9b89acdb722b35c20b3704.png

正在学习Rust的小伙伴,千万不要错过。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
04-22 31

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值