Rust 入门教程

目录

  1. 安装与环境配置
  2. Hello World
  3. 变量与基本类型
  4. 所有权(核心概念)
  5. 函数与控制流
  6. 结构体与枚举
  7. 错误处理
  8. 泛型与 Trait

1. 安装与环境配置

# 安装 Rust(使用 rustup)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# 验证安装
rustc --version
cargo --version

# 更新 Rust
rustup update

IDE 推荐

  • VS Code + rust-analyzer 插件
  • RustRover(JetBrains)
  • vim/neovim + rust-analyzer LSP

2. Hello World

# 创建项目
cargo new hello_rust
cd hello_rust
// src/main.rs
fn main() {
    println!("Hello, Rust!");
}
# 编译并运行
cargo run

# 只编译(不运行)
cargo build                  # debug 模式
cargo build --release        # release 模式(优化)

Cargo 常用命令

命令作用
cargo new创建新项目
cargo run编译+运行
cargo build编译
cargo check检查语法(不编译,快)
cargo test运行测试
cargo fmt格式化代码
cargo clippy代码规范检查

3. 变量与基本类型

变量默认不可变

fn main() {
    // 不可变变量(默认)
    let x = 5;
    // x = 6;  // ❌ 编译错误!

    // 可变变量
    let mut y = 5;
    y = 6;     // ✅

    // 常量(全大写,必须标注类型)
    const MAX_POINTS: u32 = 100_000;
}

基础类型

fn main() {
    // --- 整数 ---
    let a: i32 = 42;       // 有符号 32 位(默认)
    let b: u64 = 100;      // 无符号 64 位
    let c: usize = 10;     // 指针大小(数组索引用)

    // --- 浮点数 ---
    let pi: f64 = 3.14159; // 双精度(默认)
    let e: f32 = 2.71828;  // 单精度

    // --- 布尔 ---
    let is_rust_fun: bool = true;

    // --- 字符(4 字节,支持 Unicode)---
    let heart_emoji = '❤';
    let chinese = '中';

    // --- 元组 ---
    let tup: (i32, f64, char) = (500, 6.4, 'A');
    let (x, y, z) = tup;        // 解构
    println!("{}", tup.0);      // 索引访问

    // --- 数组(固定长度,栈上分配)---
    let arr: [i32; 5] = [1, 2, 3, 4, 5];
    let zeros = [0; 100];       // 100 个 0
    println!("{}", arr[0]);     // 索引访问
}

字符串

fn main() {
    // &str:字符串切片(不可变,借用)
    let s1: &str = "hello";

    // String:堆上分配,可增长
    let mut s2 = String::from("hello");
    s2.push_str(", world!");
    s2.push('!');

    // 拼接
    let s3 = format!("{s1}, {s2}");

    // 遍历
    for c in "नमस्ते".chars() {
        println!("{c}");
    }
}

4. 所有权(核心概念)

Rust 没有 GC,不需要手动 free,全靠所有权系统。

三大规则

fn main() {
    // 规则 1:每个值有且只有一个所有者
    let s1 = String::from("hello");
    let s2 = s1;              // s1 所有权转移给 s2
    // println!("{s1}");      // ❌ s1 已失效!

    // 规则 2:离开作用域自动释放
    {
        let s3 = String::from("world");
    }  // s3 在这里自动释放

    // 规则 3:同一时刻,要么一个可变引用,要么多个不可变引用
    let mut s = String::from("hello");

    let r1 = &s;    // 不可变借用
    let r2 = &s;    // 可以有多个不可变借用
    // let r3 = &mut s; // ❌ 不能同时有可变和不可变借用
    println!("{r1} {r2}"); // r1, r2 最后使用

    let r3 = &mut s; // ✅ r1, r2 已经不用了
    r3.push_str(" world");
}

借用可视化

所有者: s ──→ String "hello"
              │
不可变借用: r1 ──┤  (同时可以有很多个)
              r2 ──┘
              │
可变借用:   r3 ────→ (只能有一个,且不能与不可变借用共存)

5. 函数与控制流

fn main() {
    // 调用函数
    let result = add(3, 5);
    println!("3 + 5 = {result}");

    // --- if 是表达式 ---
    let number = 42;
    let description = if number > 50 {
        "big"
    } else if number > 0 {
        "positive"
    } else {
        "zero or negative"
    };
    println!("{number} is {description}");

    // --- loop ---
    let mut count = 0;
    let result = loop {
        count += 1;
        if count == 10 {
            break count * 2;  // break 可以返回值
        }
    };
    println!("loop result: {result}");

    // --- while ---
    let mut n = 3;
    while n > 0 {
        println!("{n}!");
        n -= 1;
    }
    println!("LIFTOFF!");

    // --- for(最常用)---
    let arr = [10, 20, 30, 40, 50];
    for element in arr {
        println!("the value is: {element}");
    }
    // 范围
    for i in (1..4).rev() {  // 3, 2, 1
        println!("{i}");
    }
}

// 函数定义
fn add(x: i32, y: i32) -> i32 {
    x + y  // 最后一行是返回值(不加分号)
    // 等价于 return x + y;
}

6. 结构体与枚举

结构体

// 普通结构体
struct User {
    username: String,
    email: String,
    active: bool,
}

// 元组结构体
struct Color(u8, u8, u8);
struct Point(i32, i32);

// 单元结构体(标记类型)
struct AlwaysEqual;

impl User {
    // 关联函数(构造函数)
    fn new(username: String, email: String) -> Self {
        Self {
            username,
            email,
            active: true,
        }
    }

    // 方法
    fn deactivate(&mut self) {
        self.active = false;
    }

    fn is_active(&self) -> bool {
        self.active
    }
}

fn main() {
    // 创建实例
    let mut user = User::new(
        String::from("alice"),
        String::from("alice@example.com"),
    );

    user.deactivate();
    println!("active: {}", user.is_active());

    let black = Color(0, 0, 0);
    println!("red: {}", black.0);
}

枚举与模式匹配

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

impl Message {
    fn call(&self) {
        match self {
            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!("Color: ({r}, {g}, {b})"),
        }
    }
}

// Option<T>:标准库中最常用的枚举
fn divide(a: f64, b: f64) -> Option<f64> {
    if b == 0.0 {
        None
    } else {
        Some(a / b)
    }
}

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

    // 处理 Option
    match divide(10.0, 2.0) {
        Some(result) => println!("Result: {result}"),
        None => println!("Cannot divide by zero"),
    }

    // if let 简化
    let config_max = Some(3u8);
    if let Some(max) = config_max {
        println!("Max configured: {max}");
    }
}

7. 错误处理

可恢复错误:Result<T, E>

use std::fs::File;
use std::io::{self, Read};

fn read_username_from_file() -> Result<String, io::Error> {
    // 方式 1:match
    let mut file = match File::open("username.txt") {
        Ok(f) => f,
        Err(e) => return Err(e),
    };

    let mut username = String::new();
    match file.read_to_string(&mut username) {
        Ok(_) => Ok(username),
        Err(e) => Err(e),
    }
}

// 方式 2:? 运算符(简洁版)
fn read_username_short() -> Result<String, io::Error> {
    let mut username = String::new();
    File::open("username.txt")?.read_to_string(&mut username)?;
    Ok(username)
}

// 方式 3:标准库一行版
fn read_username_oneliner() -> Result<String, io::Error> {
    std::fs::read_to_string("username.txt")
}

fn main() {
    match read_username_short() {
        Ok(name) => println!("Username: {name}"),
        Err(e) => eprintln!("Error: {e}"),
    }
}

不可恢复错误:panic!

fn main() {
    // 开发时使用
    let v = vec![1, 2, 3];
    // v[99];  // panic! 索引越界

    // 手动触发
    panic!("Something went horribly wrong!");
}

8. 泛型与 Trait

// 泛型函数
fn largest<T: std::cmp::PartialOrd>(list: &[T]) -> &T {
    let mut largest = &list[0];
    for item in list {
        if item > largest {
            largest = item;
        }
    }
    largest
}

// Trait 定义
trait Summary {
    fn summarize(&self) -> String;

    // 默认实现
    fn summarize_default(&self) -> String {
        String::from("(Read more...)")
    }
}

struct Article {
    title: String,
    content: String,
}

impl Summary for Article {
    fn summarize(&self) -> String {
        format!("{} - {}", self.title, &self.content[..50.min(self.content.len())])
    }
}

// Trait 作为参数
fn notify(item: &impl Summary) {
    println!("Breaking news! {}", item.summarize());
}

// 等价写法(trait bound)
fn notify2<T: Summary>(item: &T) {
    println!("Breaking news! {}", item.summarize());
}

fn main() {
    let numbers = vec![3, 7, 2, 9, 1];
    println!("Largest: {}", largest(&numbers));

    let article = Article {
        title: String::from("Rust is awesome!"),
        content: String::from("Learn Rust today. It will change your life."),
    };
    notify(&article);
}

标签: none

评论已关闭