Rust 简介和特性

1. Rust 简介

Rust 是一种系统编程语言,由 Mozilla 开发,旨在提供内存安全、并发性和高性能。Rust 的设计哲学是“安全、并发、实用”,它通过所有权系统、借用检查和生命周期等机制来保证内存安全,同时提供了丰富的并发编程支持。

1.1 Rust 的主要特性

  • 内存安全:Rust 通过所有权系统、借用检查和生命周期机制来防止常见的内存错误,如空指针引用、数据竞争等。
  • 并发性:Rust 提供了强大的并发编程支持,包括线程、消息传递和共享状态等。
  • 高性能:Rust 的编译器优化和零成本抽象使得生成的代码具有很高的性能。
  • 现代语法:Rust 的语法设计现代且富有表现力,支持泛型、特质(Traits)、模式匹配等高级特性。

2. 环境搭建

在开始编写 Rust 程序之前,我们需要搭建 Rust 的开发环境。Rust 的安装和管理主要通过 rustup 工具进行,而项目的构建和管理则通过 cargo 工具完成。

2.1 安装 Rust

首先,我们需要安装 rustup,这是 Rust 的安装和管理工具。可以通过以下命令在终端中安装:

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

安装完成后,可以通过以下命令验证安装是否成功:

rustc --version
cargo --version

2.2 使用 Cargo

cargo 是 Rust 的包管理器和构建工具。它可以帮助我们创建项目、管理依赖、构建和运行代码。

2.2.1 创建新项目

使用 cargo 创建一个新的 Rust 项目:

cargo new hello_world
cd hello_world

这会创建一个名为 hello_world 的新项目,包含一个基本的项目结构:

hello_world/
├── Cargo.toml
└── src
    └── main.rs
  • Cargo.toml:项目的配置文件,包含项目的元数据和依赖。
  • src/main.rs:项目的入口文件,包含 main 函数。

2.2.2 构建和运行项目

在项目目录下,可以使用以下命令构建和运行项目:

cargo build
cargo run

cargo build 会编译项目,生成可执行文件;cargo run 则会编译并运行项目。

3. 创建第一个 Rust 程序

让我们在 src/main.rs 文件中编写第一个 Rust 程序,输出 "Hello, Rust!"。

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

保存文件后,使用 cargo run 运行程序,你将看到输出:

Hello, Rust!

4. 变量和数据类型

Rust 是一种静态类型语言,这意味着所有变量在编译时都必须具有明确的类型。Rust 支持多种基本数据类型,包括整数、浮点数、布尔值和字符。

4.1 变量声明

在 Rust 中,变量默认是不可变的(immutable)。要声明一个变量,使用 let 关键字:

let x = 5;

如果你想让变量可变,可以使用 mut 关键字:

let mut y = 10;
y = 20;

4.2 数据类型

Rust 支持多种基本数据类型:

  • 整数类型:i8, i16, i32, i64, i128, u8, u16, u32, u64, u128
  • 浮点数类型:f32, f64
  • 布尔类型:bool
  • 字符类型:char

例如:

let a: i32 = 42;
let b: f64 = 3.14;
let c: bool = true;
let d: char = 'R';

5. 控制流

Rust 提供了多种控制流语句,包括 if、loop、while 和 for。

5.1 if 语句

if 语句用于条件判断:

let number = 5;

if number < 10 {
    println!("The number is less than 10");
} else {
    println!("The number is greater than or equal to 10");
}

5.2 loop 循环

loop 用于无限循环,直到使用 break 语句退出:

let mut count = 0;

loop {
    count += 1;
    if count == 5 {
        break;
    }
    println!("Count: {}", count);
}

5.3 while 循环

while 循环在条件为真时执行:

let mut count = 0;

while count < 5 {
    count += 1;
    println!("Count: {}", count);
}

5.4 for 循环

for 循环用于遍历集合:

let numbers = [1, 2, 3, 4, 5];

for number in numbers.iter() {
    println!("Number: {}", number);
}

6. 所有权系统

Rust 的核心特性之一是所有权系统,它通过所有权、借用和生命周期机制来保证内存安全。

6.1 所有权

在 Rust 中,每个值都有一个所有者(owner),并且同一时间只能有一个所有者。当所有者超出作用域时,值会被自动释放。

fn main() {
    let s1 = String::from("hello");
    let s2 = s1;  // s1 的所有权被转移给 s2

    // println!("{}", s1);  // 这行代码会导致编译错误,因为 s1 的所有权已经被转移
    println!("{}", s2);
}

6.2 借用

借用(borrowing)允许我们在不转移所有权的情况下访问值。借用分为不可变借用和可变借用。

fn main() {
    let s1 = String::from("hello");
    let len = calculate_length(&s1);  // 不可变借用

    println!("The length of '{}' is {}.", s1, len);
}

fn calculate_length(s: &String) -> usize {
    s.len()
}

7. 借用和引用

引用(reference)是借用的一种形式,允许我们在不转移所有权的情况下访问值。引用分为不可变引用和可变引用。

7.1 不可变引用

不可变引用允许我们读取值,但不能修改它:

fn main() {
    let s1 = String::from("hello");
    let len = calculate_length(&s1);

    println!("The length of '{}' is {}.", s1, len);
}

fn calculate_length(s: &String) -> usize {
    s.len()
}

7.2 可变引用

可变引用允许我们修改值,但同一时间只能有一个可变引用:

fn main() {
    let mut s1 = String::from("hello");
    change(&mut s1);

    println!("{}", s1);
}

fn change(s: &mut String) {
    s.push_str(", world");
}

8. 生命周期

生命周期(lifetime)是 Rust 中用于确保引用有效的机制。生命周期注解用于显式指定引用的有效范围。

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

fn main() {
    let string1 = String::from("long string is long");
    let result;
    {
        let string2 = String::from("xyz");
        result = longest(string1.as_str(), string2.as_str());
    }
    println!("The longest string is {}", result);
}

9. 结构体和枚举

9.1 结构体

结构体(struct)是自定义数据类型,允许我们将多个相关的值组合在一起。

struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

fn main() {
    let user1 = User {
        email: String::from("[email protected]"),
        username: String::from("someusername123"),
        active: true,
        sign_in_count: 1,
    };

    println!("User: {} <{}>", user1.username, user1.email);
}

9.2 枚举

枚举(enum)允许我们定义一个类型,该类型的值可以是多个可能的变体之一。

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}

fn main() {
    let msg = Message::Write(String::from("hello"));

    match msg {
        Message::Quit => println!("Quit"),
        Message::Move { x, y } => println!("Move to ({}, {})", x, y),
        Message::Write(text) => println!("Write: {}", text),
        Message::ChangeColor(r, g, b) => println!("Change color to ({}, {}, {})", r, g, b),
    }
}

10. 模式匹配

模式匹配(pattern matching)是 Rust 中一种强大的控制流工具,允许我们根据值的结构进行匹配。

fn main() {
    let number = 7;

    match number {
        1 => println!("One"),
        2 | 3 | 5 | 7 | 11 => println!("This is a prime"),
        13..=19 => println!("A teen"),
        _ => println!("Ain't special"),
    }
}

11. 模块系统

Rust 的模块系统允许我们将代码组织成模块(module),并通过路径(path)来访问模块中的项。

11.1 定义模块

在 src/lib.rs 或 src/main.rs 中定义模块:

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {
            println!("Added to waitlist");
        }
    }
}

fn main() {
    front_of_house::hosting::add_to_waitlist();
}

11.2 使用 use 关键字

use 关键字用于将模块中的项引入当前作用域:

use front_of_house::hosting;

fn main() {
    hosting::add_to_waitlist();
}

12. Cargo 包管理器

Cargo 是 Rust 的包管理器和构建工具,用于管理项目的依赖、构建和发布。

12.1 添加依赖

在 Cargo.toml 文件中添加依赖:

[dependencies]
rand = "0.8"

然后在代码中使用依赖:

use rand::Rng;

fn main() {
    let secret_number = rand::thread_rng().gen_range(1..101);
    println!("Secret number: {}", secret_number);
}

12.2 发布 crate

使用 cargo publish 命令可以将你的 crate 发布到 crates.io,供其他人使用。

13. 创建和发布 crate

13.1 创建 crate

使用 cargo new 命令创建一个新的 crate:

cargo new my_crate --lib

13.2 发布 crate

在发布之前,确保你的 crate 已经准备好,并且 Cargo.toml 文件中包含所有必要的信息。然后使用以下命令发布:

cargo publish

14. 使用外部依赖

在 Cargo.toml 文件中添加外部依赖,并在代码中使用:

[dependencies]
serde = { version = "1.0", features = ["derive"] }
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let point = Point { x: 1, y: 2 };
    let serialized = serde_json::to_string(&point).unwrap();
    println!("serialized = {}", serialized);
}

15. 泛型

泛型(generics)允许我们编写适用于多种类型的代码。

fn largest<T: PartialOrd>(list: &[T]) -> &T {
    let mut largest = &list[0];

    for item in list {
        if item > largest {
            largest = item;
        }
    }

    largest
}

fn main() {
    let numbers = vec![34, 50, 25, 100, 65];
    let result = largest(&numbers);
    println!("The largest number is {}", result);
}

16. 特质(Traits)

特质(traits)类似于其他语言中的接口,定义了类型必须实现的方法。

trait Summary {
    fn summarize(&self) -> String;
}

struct NewsArticle {
    headline: String,
    location: String,
    author: String,
    content: String,
}

impl Summary for NewsArticle {
    fn summarize(&self) -> String {
        format!("{}, by {} ({})", self.headline, self.author, self.location)
    }
}

fn main() {
    let article = NewsArticle {
        headline: String::from("Penguins win the Stanley Cup Championship!"),
        location: String::from("Pittsburgh, PA, USA"),
        author: String::from("Iceburgh"),
        content: String::from("The Pittsburgh Penguins once again are the best hockey team in the NHL."),
    };

    println!("New article available! {}", article.summarize());
}

17. 错误处理

Rust 提供了多种错误处理机制,包括 Result 和 Option。

17.1 Result 类型

Result 类型用于处理可能失败的计算:

fn divide(a: i32, b: i32) -> Result<i32, String> {
    if b == 0 {
        Err(String::from("Cannot divide by zero"))
    } else {
        Ok(a / b)
    }
}

fn main() {
    let result = divide(10, 2);
    match result {
        Ok(value) => println!("Result: {}", value),
        Err(e) => println!("Error: {}", e),
    }
}

17.2 Option 类型

Option 类型用于处理可能不存在的值:

fn find_even(numbers: &[i32]) -> Option<i32> {
    for &number in numbers {
        if number % 2 == 0 {
            return Some(number);
        }
    }
    None
}

fn main() {
    let numbers = [1, 3, 5, 7, 8, 9];
    match find_even(&numbers) {
        Some(even) => println!("Found an even number: {}", even),
        None => println!("No even numbers found"),
    }
}

18. 智能指针

智能指针(smart pointers)是 Rust 中一种特殊的类型,它们拥有指向数据的指针,并提供额外的功能,如