为什么 Rust 纯净代码不是奢侈品,而是必需品
\n\nRust 是一种对开发者要求严格的语言。这里的编译器严格但公正:它不容忍内存上的粗心大意,但作为回报,它提供了惊人的速度和安全性。然而,要真正释放 Rust 的潜力,仅仅让代码通过编译是不够的。你需要编写 纯净代码——清晰、可维护且优雅的代码。
\n\n在本文中,我们将探讨如何编写 Rust 纯净代码,让你的项目不会变成由 unsafe 块和复杂泛型构成的迷宫。你将了解命名原则、所有权管理的惯用法、错误处理以及代码结构。我们开始吧!
\n\n1. 命名:用 Rust 的语言说话
\n\n正确的命名是成功的一半。Rust 有严格的约定,违反这些约定就像在 code review 中挥舞红布一样(尤其引人注目)。
\n\n基本规则
\n- \n
- 变量、函数、方法和模块使用 snake_case。 \n
- 类型(struct、enum、trait)使用 PascalCase。 \n
- 常量和静态变量使用 SCREAMING_SNAKE_CASE。 \n
示例:
\n\n// 不好\nlet UserName = "Alice";\nfn GetUserData() {}\nconst MAX_SIZE: u32 = 100;\n\n// 好\nlet user_name = "Alice";\nfn get_user_data() {}\nconst MAX_SIZE: u32 = 100;\n\n避免缩写(除非显而易见)
\n与其写 calc_avg(),不如写 calculate_average()。与其用 tmp,不如用 temp_buffer。Rust 鼓励可读性,而非简洁性。
建议:如果你编写一个接受闭包的函数,请使用名称 f、g 或 closure——这是普遍接受的做法。
2. 所有权与借用:与编译器友好相处
\n\n所有权系统是 Rust 的核心。纯净代码尊重 ownership 和 borrowing 的规则,不会试图通过不必要的 clone() 或 Rc 来绕过它们。
规则:优先选择借用而非所有权
\n如果函数不需要获取所有权,请接受引用 &T 或可变引用 &mut T。
// 不好:多余的 clone\nfn process(data: Vec<i32>) {\n let mut sum = 0;\n for &val in &data {\n sum += val;\n }\n println!("Sum: {}", sum);\n}\n\n// 好:借用\nfn process(data: &[i32]) {\n let mut sum = 0;\n for &val in data {\n sum += val;\n }\n println!("Sum: {}", sum);\n}\n\n避免过度克隆
\n如果你需要将数据传递到多个地方,请使用 Rc(用于单线程场景)或 Arc(用于多线程场景)。但不要滥用:对于简单情况,引用就足够了。
3. 错误处理:放弃恐慌
\n\n在 Rust 中,有两种主要的错误处理方式:panic!(不可恢复错误)和 Result<T, E>(可恢复错误)。纯净代码尽可能使用 Result。恐慌是用于真正异常情况(例如除以零)的最后手段。
使用 ? 运算符
\n这是一种将错误向上传播的简洁方式。与其使用冗长的 match,不如这样写:
use std::fs::File;\nuse std::io::Read;\n\nfn read_file(path: &str) -> Result<String, std::io::Error> {\n let mut file = File::open(path)?;\n let mut contents = String::new();\n file.read_to_string(&mut contents)?;\n Ok(contents)\n}\n\n创建自定义错误类型
\n与其使用 String 作为错误,不如定义一个枚举:
#[derive(Debug)]\nenum MyError {\n Io(std::io::Error),\n Parse(std::num::ParseIntError),\n}\n\nimpl From<std::io::Error> for My