Rust 与 JavaScript:语法差异与心智模型对比
面向 JS/TS 开发者的 Rust 指南:变量、可变性、函数、错误处理、结构体与类、以及内存管理模型的核心差异。
对于从 JavaScript 或 TypeScript 转到 Rust 的开发者来说,Rust 的语法表面上看相当亲切(大括号、let、闭包箭头函数等)。然而,在这层相似的外表下,两者底层的运行模型与内存架构有着天壤之别。
像给 10 岁孩子解释:租房公寓 vs 私人精密车间#
- JavaScript (全托管租房公寓): 你直接搬进去住,水电随开随用,垃圾也可以顺手堆在走廊。后台有一位清洁阿姨(垃圾回收器 Garbage Collector)定期四处巡视清理。如果你找一个不存在的东西,系统会返回
undefined或null。 - Rust (自持精密机械车间): 每一把螺丝刀和扳手都有墙上的专属挂钩和唯一的法定持有者。任何借用与移动都必须严格记录。没有后台清洁阿姨——工具在离开房间的一毫秒内就会自动完成清理(RAII 编译期确定性销毁)。
graph TD
subgraph JavaScript ["JavaScript 运行时模型"]
JSEval["动态类型 & 对象模型"] --> JSHeap["V8 引擎堆内存"]
JSHeap --> GC["后台垃圾回收器(定期暂停线程)"]
JSEval --> JSNull["null / undefined(运行时抛出 TypeError)"]
end
subgraph Rust ["Rust 编译期模型"]
RustEval["静态强类型系统"] --> RustCheck["所有权与借用检查器"]
RustCheck --> Bin["零开销机器码(无 GC,RAII 确定性析构)"]
RustEval --> RustEnum["Option<T> & Result<T, E>(编译期强制处理)"]
end
1. 变量与可变性(Mutability)#
在 JavaScript 中,const 仅阻止重新绑定引用,对象内部属性依然可以随时篡改。而在 Rust 中,let 声明的变量默认是彻底不可变的(Deep Immutability)。
javascript.js
// JS: let 可重新赋值,const 仅防止重新绑定
let x = 10;
x = 20; // 正常
const user = { name: "Alice" };
user.name = "Bob"; // 正常!对象内部字段依然可变javascriptrust.rs
// Rust: 默认不可变,修改必须显式加上 'mut'
let x = 10;
// x = 20; // ❌ 编译报错: cannot assign twice to immutable variable
let mut y = 10;
y = 20; // ✅ 正常
struct User { name: String }
let user = User { name: String::from("Alice") };
// user.name = String::from("Bob"); // ❌ 编译报错: user 未声明为 mutrust2. 函数与隐式返回值(Implicit Returns)#
在 Rust 中,代码块末尾不加分号 ; 的最后一个表达式会被自动当作函数的返回值。
javascript.js
// JavaScript
function add(a, b) {
return a + b;
}
const multiply = (a, b) => a * b; // 箭头函数隐式返回javascriptrust.rs
// Rust: 必须声明类型;省略末尾 ';' 即可隐式返回
fn add(a: i32, b: i32) -> i32 {
a + b // 无分号 -> 自动 return
}
// 闭包(匿名函数)
let multiply = |a: i32, b: i32| a * b;rust3. 对象/类 vs 结构体/Trait#
JavaScript 使用基于原型/Class 的面向对象模型,并依赖 this。Rust 则将数据(struct)、行为(impl)和接口契约(trait)解耦。
javascript.js
// JavaScript Class
class Rectangle {
constructor(width, height) {
this.width = width;
this.height = height;
}
area() {
return this.width * this.height;
}
}
const rect = new Rectangle(10, 20);
console.log(rect.area());javascriptrust.rs
// Rust: 结构体(数据) + Impl 块(行为方法)
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// 关联函数(构造函数命名惯例)
fn new(width: u32, height: u32) -> Self {
Rectangle { width, height }
}
// 接收 &self 引用的方法
fn area(&self) -> u32 {
self.width * self.height
}
}
fn main() {
let rect = Rectangle::new(10, 20);
println!("面积: {}", rect.area());
}rust4. null / undefined vs Option<T>#
JavaScript 中最常见的线上崩溃就是 TypeError: Cannot read properties of undefined。Rust 在编译期彻底消灭了 null,转而使用枚举 Option<T>。
graph LR
JSNullCheck["JS: user?.address?.city"] -->|运行时遇到 undefined| Crash["未捕获的 TypeError 导致应用崩溃"]
RustOption["Rust: Option<String>"] -->|编译器强制 match 校验| SafeHandling["编译期提供 100% 安全保障"]
javascript.js
// JS: 可能返回 null 或 undefined
function findUser(id) {
if (id === 1) return { name: "Alice" };
return null;
}
const user = findUser(2);
// console.log(user.name); // ❌ 运行时报错: Cannot read properties of nulljavascriptrust.rs
// Rust: 强制返回 Option<User>
struct User { name: String }
fn find_user(id: u32) -> Option<User> {
if id == 1 {
Some(User { name: String::from("Alice") })
} else {
None
}
}
fn main() {
let user = find_user(2);
// 编译器强制要求必须处理 None 分支!
match user {
Some(u) => println!("用户名: {}", u.name),
None => println!("未找到该用户"),
}
}rust5. 错误处理:try/catch vs Result<T, E>#
JavaScript 使用异常抛出机制(throw),会跨越调用栈造成隐式跳转。Rust 将错误视为普通返回值,统一使用枚举 Result<T, E>。
javascript.js
// JS: try / catch / throw
try {
const data = JSON.parse(rawText);
console.log(data);
} catch (err) {
console.error("JSON 解析失败:", err.message);
}javascriptrust.rs
// Rust: Result<T, E> 与 ? 错误传播运算符
fn parse_number(s: &str) -> Result<i32, std::num::ParseIntError> {
let num = s.trim().parse::<i32>()?;
Ok(num * 2)
}
fn main() {
match parse_number("42") {
Ok(val) => println!("计算结果: {val}"),
Err(e) => eprintln!("解析错误: {e}"),
}
}rust核心特性快速对照表#
| 对比维度 | JavaScript / TypeScript | Rust |
|---|---|---|
| 类型系统 | 动态类型 (JS) / 结构化静态 (TS) | 静态类型、名义类型 (Nominal)、强类型 |
| 内存管理 | 垃圾回收器 (V8 GC) | 所有权机制 (Ownership) 与 RAII |
| 缺失值表示 | null 与 undefined | Option<T> (Some 或 None) |
| 错误处理 | try / catch / throw 异常 | Result<T, E> 与 ? 运算符 |
| 异步模型 | 单线程事件循环 (Promise) | 多线程异步运行时 (Tokio / Future) |
| 包管理工具 | npm / bun / pnpm (package.json) | cargo (Cargo.toml) |
| 不变性保证 | const(仅限制浅层引用) | let(默认深层绝对不可变) |
总结#
- Rust 语法对 JS/TS 开发者极为友好,但语义在编译期受到极其严格的法律级检验。
- 不可变性是 Rust 的默认规则,修改必须显式标注
mut。 - 摒弃了面向对象继承,采用
struct数据组合与trait接口实现。 Option与Result全面替代了null与异常,将运行时错误前置为编译期提醒。