参考资料:
菜鸟教程-Rust教程
Rust一门赋予每个人构建可靠且高效软件能力的语言。
一、环境搭建与项目结构
安装工具链
| JavaScript | Rust |
|---|---|
nvm 管理 Node 版本 |
rustup 管理 Rust 版本 |
npm / yarn / pnpm 包管理 |
cargo 包管理兼构建工具 |
package.json 项目配置 |
Cargo.toml 项目配置 |
bash
# 安装 Rust(类似 nvm install)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 验证安装
rustc --version # 编译器
cargo --version # 包管理器
创建新项目
bash
# JavaScript
npm init -y
# Rust
cargo new my-project
cd my-project && cargo run
Rust 项目结构:
my-project/
├── Cargo.toml # 依赖与元数据(≈ package.json)
├── Cargo.lock # 锁定依赖版本(≈ package-lock.json)
└── src/
└── main.rs # 入口文件(≈ index.js)
添加依赖
bash
# JavaScript
npm install express
# Rust
cargo add axum tokio --features full
| 部分 | 含义 |
|---|---|
cargo add |
Cargo 的子命令,用于向 Cargo.toml 添加依赖(≈ npm install) |
axum |
第一个要添加的 crate:Web 框架(类似 Express) |
tokio |
第二个要添加的 crate:异步运行时(类似 Node.js 的事件循环引擎) |
--features full |
为添加的依赖启用名为 full 的特性 |
什么是 --features full?
Rust crate 可以通过特性(features)来模块化功能,避免编译不必要的代码:
tokio 的 full 特性:启用所有子模块(rt-multi-thread、macros、net、time、fs 等),方便开发时"一把梭",不用逐个挑选
axum 的 full 特性:启用所有可选功能(如 multipart、ws、macros 等)
Cargo.toml 示例:
toml
[package]
name = "my-api"
version = "0.1.0"
edition = "2024"
[dependencies]
axum = "0.8"
tokio = { version = "1.49", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
二、核心语法对比
1. 变量声明
| JavaScript | Rust |
|---|---|
let / const / var |
let(可变)/ let mut(可变) |
| 动态类型 | 静态类型,编译器推断 |
javascript
// JavaScript
const name = "Alice";
let count = 0;
count = 1; // ✅
name = "Bob"; // ❌ TypeError
rust
// Rust
let name = "Alice"; // 默认不可变(≈ const)
let mut count = 0; // 显式声明可变
count = 1; // ✅
name = "Bob"; // ❌ 编译错误!
关键区别: Rust 中变量默认不可变。要修改必须加
mut,这比 JS 的const更严格,能在编译期防止意外修改。
2. 数据类型
| JavaScript | Rust |
|---|---|
number |
i32, i64, f32, f64(明确位数) |
string |
String(堆分配,可变)/ &str(字符串切片) |
boolean |
bool |
null / undefined |
Option<T>(显式空值处理) |
Array |
Vec<T>(动态数组) |
Object |
struct(结构体) |
rust
// Rust 基础类型
let age: i32 = 25; // 32位整数
let price: f64 = 19.99; // 64位浮点
let is_active: bool = true;
let names: Vec<String> = vec!["Alice".to_string(), "Bob".to_string()];
// 结构体(≈ JS Object)
struct User {
name: String,
age: u32,
}
let user = User {
name: String::from("Alice"),
age: 30,
};
3. 函数定义
javascript
// JavaScript
function add(a, b) {
return a + b;
}
const greet = (name) => `Hello, ${name}!`;
rust
// Rust
fn add(a: i32, b: i32) -> i32 {
a + b // 最后一行表达式自动返回(无需 return;无分号)
}
fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}
注意: Rust 函数参数和返回值必须标注类型。表达式末尾无分号表示返回值。
4. 控制流
两者非常相似:
javascript
// JavaScript
if (score >= 90) {
console.log("A");
} else if (score >= 80) {
console.log("B");
} else {
console.log("C");
}
for (let i = 0; i < 5; i++) {
console.log(i);
}
const result = age >= 18 ? "adult" : "minor";
rust
// Rust
if score >= 90 {
println!("A");
} else if score >= 80 {
println!("B");
} else {
println!("C");
}
for i in 0..5 {
println!("{}", i);
}
let result = if age >= 18 { "adult" } else { "minor" };
Rust 中
if是表达式,可以返回值赋值给变量,比 JS 的三元运算符更强大。
三、核心概念:所有权 vs 垃圾回收
这是 Rust 与 JavaScript 最大的区别。
JavaScript ------ 垃圾回收(GC)
javascript
let a = { name: "Alice" };
let b = a; // 引用拷贝,两者指向同一对象
b.name = "Bob"; // a.name 也变成 "Bob"
// JS 自动回收不再引用的内存,但时机不确定
Rust ------ 所有权系统
rust
let a = String::from("Alice");
let b = a; // 所有权转移!a 不再有效
// println!("{}", a); // ❌ 编译错误!a 已被 move
println!("{}", b); // ✅ "Alice"
三条所有权规则:
- 每个值有且只有一个所有者
- 当所有者离开作用域,值被自动释放
- 所有权可以转移(move)、借用(borrow)或复制(copy)
借用(Borrowing)
如果不想转移所有权,使用引用:
rust
let s = String::from("hello");
// 不可变借用(≈ JS 只读引用)
let len = calculate_length(&s);
println!("{} 长度是 {}", s, len); // ✅ s 仍可用
// 可变借用
let mut s = String::from("hello");
change(&mut s); // 同时只能有一个可变借用
fn calculate_length(s: &String) -> usize {
s.len() // 不获取所有权,只是借用
}
fn change(s: &mut String) {
s.push_str(", world");
}
| 方法 | 来源 | 说明 |
|---|---|---|
String::from("hello") |
std::string::String |
从 &str 字面量创建一个可变的 String |
s.len() |
std::string::String(通过 Deref 调用 str::len) |
返回字符串字节长度 |
s.push_str(", world") |
std::string::String |
追加字符串切片,不获取所有权 |
类比: JS 中你随意传递对象引用;Rust 中编译器会追踪谁拥有数据、谁在借用,确保没有悬垂指针或数据竞争。
四、错误处理
JavaScript ------ try/catch + throw
javascript
function divide(a, b) {
if (b === 0) throw new Error("除零错误");
return a / b;
}
try {
const result = divide(10, 0);
} catch (err) {
console.error(err.message);
}
Rust ------ Result<T, E> 与 Option<T>
Rust 强制你处理错误,没有 try/catch:
rust
// 可能失败的函数返回 Result
fn divide(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 {
Err(String::from("除零错误"))
} else {
Ok(a / b)
}
}
// 方式 1:match 显式处理
match divide(10.0, 0.0) {
Ok(result) => println!("结果: {}", result),
Err(e) => println!("错误: {}", e),
}
// 方式 2:? 传播错误(≈ await 的自动传播)(最常用)
fn calculate() -> Result<f64, String> {
let r1 = divide(10.0, 2.0)?; // 失败时自动返回 Err
let r2 = divide(r1, 5.0)?;
Ok(r2)
}
// 方式 3:unwrap(生产环境慎用,会 panic)
let result = divide(10.0, 2.0).unwrap();
match 是 Rust 模式匹配的核心语法,配合 Result<T, E> 实现了编译期强制错误处理。它的本质是:
"告诉我所有可能的情况,否则我不让你编译通过。"
Option<T> ------ 替代 null:
rust
fn find_user(id: u32) -> Option<User> {
if id == 1 {
Some(User { name: "Alice".to_string(), age: 30 })
} else {
None // 没有 null,只有显式的 None
}
}
// 安全访问
if let Some(user) = find_user(1) {
println!("找到: {}", user.name);
}
对比总结: JS 的错误可能在运行时抛出;Rust 的错误是类型系统的一部分,必须在编译期处理,杜绝了未捕获异常。
五、异步编程
JavaScript ------ 事件循环 + Promise
javascript
async function fetchData() {
const response = await fetch("https://api.example.com/data");
const data = await response.json();
return data;
}
Rust ------ async/await + 运行时(Tokio)
Rust 没有内置事件循环,需要显式引入运行时(如 Tokio):
rust
use tokio;
// #[tokio::main] 宏设置异步运行时(≈ Node.js 启动事件循环)
#[tokio::main]
async fn main() {
let result = fetch_data().await;
println!("{:?}", result);
}
async fn fetch_data() -> Result<String, reqwest::Error> {
let resp = reqwest::get("https://api.example.com/data").await?;
let body = resp.text().await?;
Ok(body)
}
宏的作用就是消除样板代码
#tokio::main 是 Rust 的属性宏(Attribute Macro),属于 Rust 宏系统的一部分。它由 tokio crate 提供,作用是自动为你的异步 main 函数设置 Tokio 运行时。
部分 含义 #[]Rust 的属性语法(类似 JavaScript 的装饰器 @decorator)tokio::main宏的名称,表示这是 tokio库中名为main的宏
宏展开后的实际代码(大致等价):
rust
#[tokio::main]
async fn main() {
println!("Hello");
let result = some_async_function().await;
}
// -----
fn main() {
// 创建 Tokio 运行时(多线程版本)
let rt = tokio::runtime::Runtime::new().unwrap();
// 在运行时中执行 async main 函数
rt.block_on(async {
println!("Hello");
let result = some_async_function().await;
})
}
关键区别: JS 的
async/await基于单线程事件循环;Rust 的async/await由 Tokio 调度到线程池,实现真正的多核并行,且编译器保证线程安全。
六、实战:REST API 对比
JavaScript (Express)
javascript
const express = require('express');
const app = express();
app.use(express.json());
app.get('/users/:id', (req, res) => {
const user = { id: req.params.id, name: "Alice" };
res.json(user);
});
app.listen(3000, () => console.log('Server on 3000'));
Rust (Axum + Tokio)
rust
use axum::{
routing::get,
Router,
extract::Path,
Json,
};
use serde::{Deserialize, Serialize};
use std::net::SocketAddr;
#[derive(Serialize)]
struct User {
id: String,
name: String,
}
async fn get_user(Path(id): Path<String>) -> Json<User> {
Json(User {
id,
name: "Alice".to_string(),
})
}
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/users/:id", get(get_user));
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
println!("Listening on {}", addr);
let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
axum::serve(listener, app).await.unwrap();
}
七、生态与工具链对比
| 维度 | JavaScript | Rust |
|---|---|---|
| 包管理 | npm (2M+ 包) | Cargo (crates.io, 150K+ 包) |
| 构建工具 | Webpack/Vite/Rollup | Cargo(内置,无需配置) |
| 代码检查 | ESLint + Prettier | Clippy(lint)+ rustfmt(格式化) |
| 测试 | Jest/Vitest | cargo test(内置) |
| 文档 | JSDoc | cargo doc + /// 注释自动生成 |
| Web 框架 | Express/Nest/Fastify | Axum/Actix-web/Rocket |
| ORM | Prisma/Drizzle/Sequelize | Diesel/SQLx/SeaORM |
| 前端 | React/Vue/Angular | Leptos/Yew/Dioxus(编译为 WASM) |
趋势: 2026 年,Rust 正在大量替代 JavaScript 工具链底层------SWC(转译)、Turbopack(打包)、Biome(代码检查)等,性能提升 10~100 倍。
八、性能与资源对比
| 指标 | JavaScript (Node.js) | Rust |
|---|---|---|
| CPU 密集型任务 | 单线程,Worker Threads 辅助 | 5~10 倍性能提升,真多核并行 |
| 内存占用 | GC 开销大,不可预测 | 无 GC,精确内存控制 |
| 启动时间 | 需 Node 运行时 | 单二进制文件,零依赖 |
| P99 延迟 | ~67ms (Bun) / 更高 (Node) | ~18ms |
| 内存使用 | ~720MB (高负载) | ~180MB (高负载) |
九、何时选择 Rust?
| 选择 Rust | 选择 JavaScript |
|---|---|
| 高性能后端服务、API 网关 | 快速原型、MVP 开发 |
| 系统工具、CLI、边缘计算 | 全栈 Web 应用、前端交互 |
| 区块链、金融科技、游戏服务器 | 需要大量 npm 生态集成的项目 |
| WebAssembly 模块 | 团队以 JS 为主,追求开发速度 |
| 内存安全要求极高的场景 | 实时协作、快速迭代的业务系统 |
十、学习路径建议(JS → Rust)
第 1 周:语法基础
├── 变量、类型、函数、控制流
└── 对比练习:把一段 JS 代码改写成 Rust
第 2 周:所有权与借用
├── 理解 move、borrow、lifetime
└── 练习:实现字符串处理工具
第 3 周:错误处理与集合
├── Result、Option、Vec、HashMap
└── 练习:命令行待办事项应用
第 4 周:异步与 Web
├── Tokio、Axum、serde
└── 练习:用 Rust 重写一个 Express API
第 5~6 周:项目实战
├── 选择一个真实项目(如文件处理器、爬虫、微服务)
└── 部署到服务器(体验单二进制部署的快感)
总结
Rust 不是 JavaScript 的替代品,而是互补工具 。JavaScript 以开发速度和生态广度见长,Rust 以性能、内存安全和可靠性取胜。现代团队越来越多采用混合架构:JS/TS 负责产品层和快速迭代,Rust 负责性能关键的核心引擎,通过 WebAssembly 或 napi-rs 无缝集成。