Please enable Javascript to view the contents

 ·  ☕ 6 分钟

我是一个 Java 程序员,现在想系统学习一下 Rust。

作为一名经验丰富的 Java 程序员,您已经掌握了编程的核心概念(如变量、循环、函数、面向对象等),这会大大加速您的学习进程。然而,Rust 的核心理念——所有权(Ownership)借用(Borrowing)生命周期(Lifetimes)——对您来说将是全新的,也是学习的重点和难点。

以下是为您量身定制的系统学习路线图,旨在帮助您平滑地从 Java 过渡到 Rust。


第一阶段:基础入门与思维转变 (1-2 周)

这个阶段的目标是熟悉 Rust 的基本语法和工具链,并开始理解其与 Java 最根本的不同。

  1. 环境搭建与工具链:
    • 安装: 使用 rustup 安装 Rust。rustup 是 Rust 的版本管理工具,类似于 Java 的 jenvsdkman
    • Cargo: 这是 Rust 的项目管理和构建工具,集成了 Maven/Gradle 的依赖管理和构建功能。学习使用 cargo new, cargo build, cargo run, cargo test
    • IDE/编辑器: 安装 VS Code 并配置 rust-analyzer 插件,它能提供类似 IntelliJ IDEA 的智能提示、代码补全和错误检查。

使用 Rust 的项目的源码文件结构是怎样的?什么是 Cargo.toml 文件? 什么是 crates ?

当然,这几个概念是理解 Rust 项目如何组织和构建的基石。对于有 Java 背景的您来说,可以将它们与 Maven/Gradle 的概念进行类比,会更容易理解。


1. Rust 项目的源码文件结构

Rust 的项目结构遵循一套简单且强大的约定。当您使用 Cargo 创建一个新项目时,它会自动生成这个标准结构。

1.1. 二进制应用 (Binary Application)

如果您要创建一个可执行程序(类似于一个包含 main 方法的 Java 项目),可以运行:

Bash

cargo new my_app

Cargo 会生成如下结构:

my_app
├── .git/
├── .gitignore
├── Cargo.toml
└── src/
    └── main.rs
  • my_app/: 项目的根目录。
  • Cargo.toml: 项目清单文件,我们稍后会详细讲解。
  • src/: 存放所有源代码的目录,完全等同于 Java 项目中的 src/main/java
  • src/main.rs: 二进制项目的根文件和入口fn main() { ... } 函数必须定义在这里,它就是程序的起点,等同于 Java 的 public static void main(String[] args) {}

1.2. 库 (Library)

如果您要创建一个可复用的库(类似于一个要打包成 JAR 的 Java 库项目),可以运行:

Bash

cargo new my_lib --lib

结构会略有不同:

my_lib
├── .git/
├── .gitignore
├── Cargo.toml
└── src/
    └── lib.rs
  • src/lib.rs: 库项目的根文件。这个文件定义了库对外暴露的公共 API。它没有 main 函数。

1.3. 模块化(组织代码)

当代码变得复杂时,您需要将其拆分到不同文件中。这类似于 Java 的包(package)。

例如,您可以这样组织代码:

src/
├── main.rs
├── network.rs
└── network/
    └── client.rs

要在 main.rs 中使用这些模块,您需要声明它们:

Rust

// 在 main.rs 中

mod network; // 声明 src/network.rs 是一个模块

fn main() {
    println!("Hello from main!");
    // 使用 network 模块中的函数或 client 子模块
    network::connect();
    network::client::ping();
}

而在 network.rs 中,您需要声明它的子模块:

Rust

// 在 src/network.rs 中

pub mod client; // 声明 network/client.rs 是一个子模块

pub fn connect() {
    println!("Connecting...");
}
  • mod network; 告诉编译器去查找 src/network.rs 或者 src/network/mod.rs 文件,并将其内容编译为一个名为 network 的模块。
  • 这套模块系统是 Rust 组织代码、控制可见性(pub 关键字)的核心。

2. Cargo.toml 文件是什么?

Cargo.toml 是 Rust 项目的清单文件,采用 TOML 格式。

它完全可以类比为 Java 世界的 pom.xml (Maven) 或 build.gradle (Gradle)。 它负责定义项目的所有元数据和依赖项。

一个典型的 Cargo.toml 文件包含以下几个部分:

Ini, TOML

# [package] 部分定义了项目的核心元数据
[package]
name = "my_app"             # 项目名称 (crate 名称)
version = "0.1.0"           # 项目版本号,遵循语义化版本
edition = "2021"            # 使用的 Rust 版本(例如 2015, 2018, 2021),会影响一些语法特性

# [dependencies] 部分定义了项目运行时需要的依赖库
# 这等同于 pom.xml 中的 <dependencies> 标签
[dependencies]
serde = { version = "1.0", features = ["derive"] } # 引入 serde 库
rand = "0.8.5"                                   # 引入 rand 库
tokio = { version = "1", features = ["full"] }    # 引入 tokio 异步运行时

# [dev-dependencies] 部分定义了仅在测试、示例或基准测试时才需要的依赖
# 这等同于 pom.xml 中 <scope>test</scope> 的依赖
[dev-dependencies]
criterion = "0.4"

核心功能

  1. 项目描述: 定义项目的名称、版本、作者等。
  2. 依赖管理: 当您在 [dependencies] 中添加一个库时,运行 cargo buildcargo run,Cargo 会自动从官方仓库 crates.io 下载并编译该依赖及其所有子依赖。
  3. 构建配置: 您还可以定义不同的构建配置(Profiles),例如为开发构建(dev)和发布构建(release)设置不同的优化级别。

3. Crates 是什么?

Crate 是 Rust 中最小的编译单元。

您可以将一个 Crate 类比为一个 Java 的 JAR 文件。它要么是一个可执行程序(Runnable JAR),要么是一个库(Library JAR)。

Crate 有两种类型:

  1. 二进制 Crate (Binary Crate):
    • 是一个可编译成可执行文件的程序。
    • 必须包含一个 fn main() 函数作为程序入口。
    • 项目的 src/main.rs 文件默认就是这个二进制 Crate 的根文件。
    • 一个项目可以包含多个二进制 Crate(例如在 src/bin/ 目录下创建多个 .rs 文件)。
  2. 库 Crate (Library Crate):
    • 是一系列功能的集合,旨在被其他项目作为依赖使用。
    • 没有 fn main() 函数。
    • src/lib.rs 文件是一个库 Crate 的根文件。
    • 一个项目(包)最多只能有一个库 Crate。

总结与类比

为了让您更好地理解这三者之间的关系,这里有一个总结:

Rust 概念 Java 类比 描述
Package Maven/Gradle 项目 一个由 Cargo.toml 文件定义的项目。一个 Package 可以包含一个库 Crate 和多个二进制 Crate。
Crate JAR 文件 一个编译单元。可以是库 (Library)可执行程序 (Binary)
Cargo.toml pom.xml / build.gradle 项目的清单和构建配置文件,用于管理元数据和依赖。
crates.io Maven Central Rust 的官方公共包(Crate)仓库。
src/main.rs src/main/java/com/mycompany/Main.java 二进制 Crate 的入口文件,包含 main 函数。
src/lib.rs src/main/java/ (整个包) 库 Crate 的根文件,定义了库的公共 API。
Module (mod) Package (package com.mycompany;) 在一个 Crate 内部组织代码、控制可见性的方式。

介绍一下 rust 项目的模块化机制

好的 👍。Rust 的模块化机制和 Java 的 package/module 概念有点像,但更底层、更接近文件系统。整体来说,Rust 的 模块系统 (module system)四个部分组成:

  • 包 (Package)
  • 板条箱 (Crate)
  • 模块 (Module)
  • 路径 (Path)

我帮你逐层对比一下 Java,让你更好理解。


1. 包 (Package)

  • 一个 package 是由一个或多个 crate 组成的集合。
  • 必须包含一个 Cargo.toml 文件,描述依赖和元数据。
  • 👉 类比:Java 里的 Maven/Gradle 项目

例子:

1
2
3
4
5
6
7
# Cargo.toml
[package]
name = "my_app"
version = "0.1.0"

[dependencies]
rand = "0.8"

2. 板条箱 (Crate)

  • crate 是编译的最小单元,可以生成 库 (library)二进制 (binary)
  • 默认情况下:
    • src/main.rs 定义一个 binary crate(类似 Java 的 public static void main 入口)。
    • src/lib.rs 定义一个 library crate(类似 Java 的库 Jar)。
  • 👉 类比:Java 的 Jar 包

例子:

1
2
cargo new mylib --lib   # 创建库 crate
cargo new myapp --bin   # 创建二进制 crate

3. 模块 (Module)

  • module 用来组织代码,相当于 Java package,但与文件系统紧密对应。
  • mod 关键字声明:
    • 可以放在同一个文件里(内联模块)。
    • 也可以拆到单独文件/目录。

例子:

单文件模块

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// src/main.rs
mod utils; // 声明有一个 utils 模块

fn main() {
    utils::greet("Mark");
}

// src/utils.rs
pub fn greet(name: &str) {
    println!("Hello, {}!", name);
}

目录模块

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// src/main.rs
mod utils;

fn main() {
    utils::math::add(1, 2);
}

// src/utils/mod.rs   (模块目录入口)
pub mod math;

// src/utils/math.rs
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

👉 Rust 的 mod.rs 类似 Java 的 package-info.java,作为目录模块的入口。

from Mark: *.rs 文件名即 mod 名。


4. 路径 (Path) 与可见性

  • Rust 默认 私有 (private),需要显式 pub 才能被外部访问。
  • 访问路径用 ::,类似 Java 的点号 .
  • 特殊关键字:
    • self:当前模块(类似 Java 的 this package)。
    • super:父模块(类似 Java 的 .. 上级包)。
    • crate:当前 crate 根(类似 Java 项目根)。

例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// src/lib.rs
pub mod network;

pub fn run() {
    crate::network::http::request();
}

// src/network/mod.rs
pub mod http;

// src/network/http.rs
pub fn request() {
    println!("HTTP request");
}

Java vs Rust 模块化对比

概念 Java Rust
项目 Maven/Gradle Project Package (Cargo.toml)
编译单元 Jar Crate (binary/lib)
命名空间 Package (com.example.util) Module (mod util;)
入口 public static void main(String[]) fn main()
可见性 public / protected / private pub (默认 private)
组织结构 文件夹 + .java 文件 文件夹 + .rs 文件 (mod.rs 可选)

⚡ 关键点总结:

  • Rust 的 模块系统是基于文件系统的,而 Java 是基于包名(字符串)。
  • Rust 默认私有,要导出必须加 pub
  • crate 是项目内的根,mod 用来声明模块。
  • 文件/目录结构 就是模块结构(跟 Java 有点像,但更严格)。

要不要我帮你画一张 Rust 模块系统结构图,用目录树和对应的 mod 声明,把 crate → module → path 的关系直观表现出来?

分享

Mark Zhu
作者
Mark Zhu
An old developer