Rust 语言快速入门:你的第一行安全代码 – wiki大全


Rust 语言快速入门:你的第一行安全代码

在当今软件开发领域,性能、并发和内存安全是构建可靠应用的关键。众多编程语言中,Rust 凭借其独特的所有权系统,在编译时确保内存安全,同时提供媲美 C/C++ 的运行时性能,成为了开发者社区的新宠。如果你渴望编写既快速又安全的代码,那么 Rust 绝对值得一试。

本文将引导你快速踏入 Rust 的世界,编写你的第一个程序,并深入了解其核心安全机制——所有权系统。

第一步:安装 Rust

Rust 的安装非常简单,推荐使用 rustup 工具链管理器。rustup 允许你管理不同版本的 Rust 编译器和相关工具。

在 Windows/macOS/Linux 上安装:

打开你的终端或 PowerShell,运行以下命令:

bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

按照提示完成安装。安装完成后,你需要重新启动终端或运行 source $HOME/.cargo/env(对于 Linux/macOS)来确保 cargorustc 命令在你的 PATH 中可用。

验证安装:

bash
rustc --version
cargo --version

如果看到版本信息,说明 Rust 已经成功安装。rustc 是 Rust 编译器,cargo 是 Rust 的构建工具和包管理器,也是你日常开发中最常使用的工具。

你的第一个 Rust 程序:Hello, World!

使用 cargo 创建一个新项目是 Rust 开发的惯用方式。这会为你设置一个标准项目结构。

  1. 创建新项目:

    bash
    cargo new hello_rust
    cd hello_rust

    cargo new hello_rust 命令创建了一个名为 hello_rust 的目录,其中包含一个 src 文件夹和一个 Cargo.toml 文件。Cargo.toml 是 Rust 项目的配置文件,类似于 package.jsonpom.xml

  2. 查看代码:

    打开 src/main.rs 文件,你会看到以下内容:

    rust
    fn main() {
    println!("Hello, world!");
    }

    • fn main():这是 Rust 程序的入口点,所有可执行的 Rust 程序都必须有一个 main 函数。
    • println!:这是一个宏(以 ! 结尾),用于向控制台打印文本。宏在 Rust 中非常常见,提供了编译时代码生成的能力。
  3. 编译并运行:

    在项目根目录(hello_rust)下,运行:

    bash
    cargo run

    cargo run 命令会先编译你的代码(如果尚未编译或有更改),然后执行生成的可执行文件。你将在终端看到输出:

    Hello, world!

    恭喜!你已经成功编写并运行了你的第一个 Rust 程序。

深入理解 Rust 的安全性:所有权系统

“安全”是 Rust 的核心卖点。它不是通过垃圾回收器(GC)来实现内存安全,而是在编译时通过一套独特的所有权系统来强制执行内存规则。这意味着在运行时几乎没有性能开销,同时又能杜绝许多常见的内存错误(如空指针解引用、数据竞争、悬垂指针等)。

让我们来理解所有权系统的几个核心概念:

1. 所有权(Ownership)

  • 定义: Rust 中的每个值都有一个变量作为它的“所有者”(owner)。
  • 规则: 在任何给定时间,一个值只能有一个所有者。
  • 生命周期: 当所有者超出其作用域(scope)时,该值将被丢弃(dropped),其占用的内存也会被自动回收。这消除了手动内存管理的需要,同时避免了垃圾回收的停顿。

示例:

“`rust
fn main() {
let s1 = String::from(“hello”); // s1 是 “hello” 字符串的所有者

// s1 在这里仍然有效

} // s1 超出作用域,”hello” 字符串的内存被释放
“`

2. 移动(Move)

当一个变量的值被赋值给另一个变量,或者作为函数参数传递时,所有权会从原变量“移动”到新变量。原变量将不再有效。

示例:

“`rust
fn main() {
let s1 = String::from(“hello”); // s1 拥有 “hello”

let s2 = s1; // 所有权从 s1 移动到 s2。s1 不再有效!

// println!("{}", s1); // 这行会引发编译错误:value borrowed here after move
println!("{}", s2); // s2 拥有 "hello",可以正常使用

}
“`

这种“移动”行为是 Rust 防止数据在内存中被多次释放(double free)的关键。

3. 借用(Borrowing)和引用(References)

如果你想在不转移所有权的情况下使用一个值,你可以“借用”它,也就是创建一个引用。引用就像一个指针,指向但不拥有数据。

规则:

  • 在任何给定时间,你只能拥有:
    • 一个可变引用 (&mut T),或者
    • 任意数量的不可变引用 (&T)。
  • 引用必须总是有效的。Rust 编译器会通过“借用检查器”(borrow checker)来强制执行这些规则,确保引用的生命周期不会超过它们所指向的数据。

示例:不可变引用

“`rust
fn calculate_length(s: &String) -> usize { // s 是对 String 的不可变引用
s.len()
} // s 超出作用域,但它不拥有数据,所以不会释放内存

fn main() {
let s1 = String::from(“hello”); // s1 拥有 “hello”

let len = calculate_length(&s1); // 将 s1 的不可变引用传递给函数

println!("The length of '{}' is {}.", s1, len); // s1 仍然有效,因为所有权没有转移

}
“`

示例:可变引用

“`rust
fn change_string(s: &mut String) { // s 是对 String 的可变引用
s.push_str(“, world!”);
}

fn main() {
let mut s = String::from(“hello”); // 声明 s 为可变

change_string(&mut s); // 传递可变引用

println!("{}", s); // 输出 "hello, world!"

}
“`

借用检查器在实践中:

“`rust
fn main() {
let mut s = String::from(“hello”);

let r1 = &mut s; // 第一个可变引用
// let r2 = &mut s; // 编译错误!不能同时有两个可变引用

// println!("{}, {}", r1, r2);

let r3 = &s; // 不可变引用
let r4 = &s; // 另一个不可变引用
// let r5 = &mut s; // 编译错误!不能在一个值存在不可变引用时创建可变引用

println!("{}, {}", r3, r4); // 它们都可以正常使用

}
“`

这些规则看起来可能有些严格,但在编译时强制执行,可以有效预防数据竞争(data race)等并发错误,尤其是在多线程环境中。Rust 编译器在发现潜在的内存安全问题时会立即报错,而不是让这些问题在运行时成为难以调试的 bug。

为什么选择 Rust?

  • 内存安全: 在编译时杜绝了大部分内存错误,无需垃圾回收。
  • 卓越性能: 无运行时开销,与 C/C++ 媲美,适合系统编程、游戏开发、嵌入式系统等。
  • 并发安全: 所有权系统使得编写线程安全的代码变得更加容易。
  • 强大的类型系统: 编译时捕获更多错误。
  • 现代工具链: cargo 作为包管理器和构建工具,极大地提高了开发效率。
  • 活跃的社区: 庞大且不断增长的社区支持。

总结与展望

通过本文,你已经成功安装了 Rust,编写了你的第一个程序,并对 Rust 最核心的安全机制——所有权系统有了初步的理解。这只是 Rust 之旅的开始。

Rust 的学习曲线可能比一些高级语言要陡峭一些,但它带来的安全性、性能和可靠性是值得付出的。随着你对所有权、借用、生命周期以及其他高级概念(如 trait、泛型、并发原语)的深入理解,你将能够编写出令人惊叹的、高性能且安全的代码。

现在,你已经迈出了“第一行安全代码”的第一步,祝你在 Rust 的世界中探索愉快!


滚动至顶部