Rust 入门(二):基础语法与核心概念

January, 7th 2026 11 min read Markdown
Rust 入门(二):基础语法与核心概念

Rust 入门系列(第 2 篇,共 5 篇) 前置阅读第 1 篇 - Rust 是什么?能做什么? 阅读时间:25 分钟


引言

这篇文章会快速过一遍 Rust 的核心语法,包括环境搭建、基础数据类型、函数、控制流、Struct/Enum 等。目标是让你能写出第一个 Rust 程序,理解基本概念。


一、环境搭建

1.1 安装 Rust

官方推荐使用 rustup

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

# Windows:访问 https://rustup.rs/ 下载安装器

安装后得到:

  • rustc:Rust 编译器
  • cargo:包管理器 + 构建工具
  • rustup:工具链管理器

验证安装:

bash
12
rustc --version
cargo --version

1.2 创建第一个项目

Cargo 官方文档

bash
12
cargo new hello_rust
cd hello_rust

目录结构:

plaintext
12345
hello_rust/
├── Cargo.toml        # 项目配置(类似 package.json)
├── src/
│   └── main.rs       # 源代码
└── target/           # 构建输出

1.3 运行项目

bash
12
cargo run
# 输出:Hello, world!

常用命令

bash
1234567
cargo build          # 编译(debug 模式)
cargo build --release  # 编译(release 模式,优化)
cargo run            # 编译 + 运行
cargo test           # 运行测试
cargo check          # 快速检查代码(不生成可执行文件)
cargo fmt            # 格式化代码
cargo clippy         # 代码检查

二、变量与可变性

2.1 默认不可变

Rust 变量默认不可变

rust
12345
let x = 5;
// x = 6;  // ❌ 错误:不能修改不可变变量

let mut y = 5;  // 需要 mut 关键字
y = 6;          // ✅ OK

为什么默认不可变?

  • 更安全:避免意外修改
  • 更容易并发:不可变数据无需加锁

2.2 变量遮蔽(Shadowing)

可以用 let 重新声明同名变量:

rust
1234
let x = 5;
let x = x + 1;  // 遮蔽前一个 x
let x = x * 2;  // 再次遮蔽
println!("{}", x);  // 12

遮蔽 vs mut

rust
1234567
// 遮蔽:可以改变类型
let spaces = "   ";
let spaces = spaces.len();  // ✅ 字符串 → 数字

// mut:不能改变类型
let mut count = "   ";
// count = count.len();  // ❌ 错误:类型不匹配

三、数据类型

3.1 标量类型

整数

长度有符号无符号
8-biti8u8
16-biti16u16
32-biti32u32
64-biti64u64
128-biti128u128
archisizeusize
rust
12345
let decimal = 98_222;      // 十进制
let hex = 0xff;            // 十六进制
let octal = 0o77;          // 八进制
let binary = 0b1111_0000;  // 二进制
let byte = b'A';           // 字节(u8)

默认类型i32

浮点数

rust
12
let x = 2.0;      // f64(默认)
let y: f32 = 3.0; // f32

布尔值

rust
12
let t = true;
let f: bool = false;

字符

rust
12
let c = 'z';
let emoji = '😻';  // Unicode 字符

3.2 复合类型

元组

rust
12345678
let tup: (i32, f64, u8) = (500, 6.4, 1);

// 解构
let (x, y, z) = tup;

// 索引访问
let five_hundred = tup.0;
let six_point_four = tup.1;

数组

rust
12345678
let arr = [1, 2, 3, 4, 5];        // 类型:[i32; 5]
let arr: [i32; 5] = [1, 2, 3, 4, 5];  // 显式标注

let arr = [3; 5];  // [3, 3, 3, 3, 3]

// 访问
let first = arr[0];
let second = arr[1];

数组 vs Vec

  • 数组:固定长度,存储在栈上
  • Vec:可变长度,存储在堆上
rust
1
let v: Vec<i32> = vec![1, 2, 3];

3.3 字符串

Rust 有两种字符串:

&str(字符串切片)

rust
1
let s: &str = "Hello, world!";  // 不可变,存储在栈

String(堆字符串)

rust
123
let mut s = String::from("Hello");
s.push_str(", world!");  // 可变
println!("{}", s);       // "Hello, world!"

转换

rust
123
let s1: &str = "Hello";
let s2: String = s1.to_string();
let s3: &str = &s2;  // String → &str

四、函数

4.1 基本语法

rust
1234567
fn add(x: i32, y: i32) -> i32 {
    x + y  // 表达式,自动返回(无分号)
}

fn add2(x: i32, y: i32) -> i32 {
    return x + y;  // 也可以用 return(需要分号)
}

4.2 无返回值

rust
12345678
fn greet(name: &str) {
    println!("Hello, {}!", name);
}

// 等价于
fn greet2(name: &str) -> () {
    println!("Hello, {}!", name);
}

4.3 语句 vs 表达式

语句:不返回值,以分号结尾

rust
1
let x = 5;  // 语句

表达式:返回值,无分号

rust
1234
let y = {
    let x = 3;
    x + 1  // 表达式,返回 4
};

五、控制流

5.1 if 表达式

rust
12345678910
let number = 6;

if number % 2 == 0 {
    println!("偶数");
} else {
    println!("奇数");
}

// if 是表达式
let result = if number < 5 { "small" } else { "big" };

5.2 循环

loop

rust
12345678
let mut counter = 0;

let result = loop {
    counter += 1;
    if counter == 10 {
        break counter * 2;  // 返回 20
    }
};

while

rust
123456
let mut number = 3;

while number != 0 {
    println!("{}", number);
    number -= 1;
}

for

rust
123456789101112131415
// 遍历范围
for i in 0..5 {
    println!("{}", i);  // 0, 1, 2, 3, 4
}

// 遍历数组
let arr = [10, 20, 30];
for element in arr.iter() {
    println!("{}", element);
}

// 带索引
for (index, value) in arr.iter().enumerate() {
    println!("{}: {}", index, value);
}

六、模式匹配

6.1 match 表达式

rust
12345678
let number = 13;

match number {
    1 => println!("One!"),
    2 | 3 | 5 | 7 | 11 => println!("Prime"),
    13..=19 => println!("A teen"),
    _ => println!("Other"),
}

6.2 匹配 Option

rust
1234567
let some_number = Some(5);
let no_number: Option<i32> = None;

match some_number {
    Some(i) => println!("Got: {}", i),
    None => println!("No value"),
}

6.3 if let 简化

rust
123456789101112
let some_value = Some(3);

// match 写法
match some_value {
    Some(3) => println!("three"),
    _ => (),
}

// if let 简化
if let Some(3) = some_value {
    println!("three");
}

七、Struct(结构体)

7.1 定义和使用

rust
123456789101112131415
struct User {
    username: String,
    email: String,
    age: u32,
    active: bool,
}

let user1 = User {
    username: String::from("alice"),
    email: String::from("[email protected]"),
    age: 25,
    active: true,
};

println!("{}", user1.username);

7.2 更新语法

rust
1234
let user2 = User {
    email: String::from("[email protected]"),
    ..user1  // 其余字段从 user1 复制
};

7.3 方法

rust
1234567891011121314
impl User {
    fn greet(&self) {
        println!("Hi, I'm {}!", self.username);
    }

    fn is_adult(&self) -> bool {
        self.age >= 18
    }
}

user1.greet();
if user1.is_adult() {
    println!("Adult");
}

7.4 关联函数

rust
12345678910111213141516
impl User {
    fn new(username: String, email: String, age: u32) -> User {
        User {
            username,
            email,
            age,
            active: true,
        }
    }
}

let user = User::new(
    String::from("alice"),
    String::from("[email protected]"),
    25
);

八、Enum(枚举)

8.1 基本用法

rust
1234567
enum IpAddr {
    V4,
    V6,
}

let ipv4 = IpAddr::V4;
let ipv6 = IpAddr::V6;

8.2 携带数据

rust
1234567
enum IpAddr {
    V4(u8, u8, u8, u8),
    V6(String),
}

let home = IpAddr::V4(127, 0, 0, 1);
let loopback = IpAddr::V6(String::from("::1"));

8.3 复杂 Enum

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

impl Message {
    fn call(&self) {
        match self {
            Message::Quit => println!("Quit"),
            Message::Move { x, y } => println!("Move to ({}, {})", x, y),
            Message::Write(text) => println!("Text: {}", text),
            Message::ChangeColor(r, g, b) => {
                println!("Color: ({}, {}, {})", r, g, b)
            }
        }
    }
}

let msg = Message::Write(String::from("Hello"));
msg.call();

九、Option 和 Result

9.1 Option:处理空值

Rust 没有 null,用 Option<T> 表示”可能有值”:

rust
1234
enum Option<T> {
    Some(T),
    None,
}

示例

rust
123456789101112
fn divide(a: i32, b: i32) -> Option<i32> {
    if b == 0 {
        None
    } else {
        Some(a / b)
    }
}

match divide(10, 2) {
    Some(result) => println!("结果: {}", result),
    None => println!("无法除以 0"),
}

常用方法

rust
12345678910
let x = Some(5);

// unwrap:有值则返回,无值则 panic
let y = x.unwrap();

// unwrap_or:无值时返回默认值
let z = x.unwrap_or(0);

// map:转换内部值
let doubled = x.map(|n| n * 2);  // Some(10)

9.2 Result:错误处理

rust
1234
enum Result<T, E> {
    Ok(T),
    Err(E),
}

示例

rust
12345678910
use std::fs::File;

fn open_file() -> Result<File, std::io::Error> {
    File::open("hello.txt")
}

match open_file() {
    Ok(file) => println!("文件打开成功"),
    Err(error) => println!("打开失败: {:?}", error),
}

? 操作符

rust
123456
fn read_username() -> Result<String, std::io::Error> {
    let mut file = File::open("username.txt")?;  // 失败则提前返回 Err
    let mut username = String::new();
    file.read_to_string(&mut username)?;
    Ok(username)
}

十、实战:完整小程序

10.1 猜数字游戏

rust
1234567891011121314151617181920212223242526272829303132
use rand::Rng;
use std::cmp::Ordering;
use std::io;

fn main() {
    println!("猜数字游戏!");

    let secret_number = rand::thread_rng().gen_range(1..=100);

    loop {
        println!("请输入你的猜测:");

        let mut guess = String::new();
        io::stdin()
            .read_line(&mut guess)
            .expect("读取失败");

        let guess: u32 = match guess.trim().parse() {
            Ok(num) => num,
            Err(_) => continue,
        };

        match guess.cmp(&secret_number) {
            Ordering::Less => println!("太小了!"),
            Ordering::Greater => println!("太大了!"),
            Ordering::Equal => {
                println!("猜对了!");
                break;
            }
        }
    }
}

Cargo.toml

toml
12
[dependencies]
rand = "0.8"

运行:

bash
1
cargo run

十一、核心概念总结

11.1 关键要点

  1. 默认不可变let x 不可变,let mut x 可变
  2. 无 null:用 Option<T> 替代
  3. 无异常:用 Result<T, E> 处理错误
  4. 类型严格:不会自动转换类型
  5. 表达式优先ifmatchloop 都可以返回值

11.2 常见困惑

问题解答
为什么没分号?表达式返回值不需要分号
&str vs String?&str 不可变切片,String 可变堆字符串
Option 有什么用?替代 null,强制处理空值情况
match 必须穷尽?是的,编译器会检查

十二、下一步

12.1 练习建议

  1. 修改猜数字游戏:加入重试次数限制
  2. 待办事项 CLI:用 Vec 存储任务
  3. 简单计算器:实现加减乘除

12.2 推荐资源


系列预告

第 3 篇:《Rust 入门(三):所有权、借用、生命周期》

  • 所有权系统详解
  • 借用和引用规则
  • 生命周期标注

第 4 篇:《Rust 入门(四):实战 CLI 工具》 第 5 篇:《Rust 入门(五):Rust + WebAssembly》


参考资料


系列导航