Skip to content

Rust 语法基础

概要

Rust 是一门强调内存安全和高性能的系统编程语言。它通过所有权机制在编译期解决大量运行时问题。

一、变量与可变性

let 声明变量时默认不可变,let mut 才允许修改。实际开发中建议优先保持不可变,这样能减少副作用,代码也更容易维护。

rust
fn main() {
  let x = 10; // 默认不可变
  let mut y = 20; // 可变
  y += 1;
  println!("x = {x}, y = {y}");
}
rust
// 常量不仅默认情况下是不可变的,而且始终是不可变的。
const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;

二、数据类型

1. 标量类型

Rust 的基础数据类型是写程序时最常接触的“积木”。你可以先记住一个原则:
简单数值优先用整数/浮点,文本优先区分 String 和 &str,布尔和字符分别用于逻辑判断与单字符处理。

类型分类常见类型说明
整数i8..i128、u8..u128、isize、usize有符号/无符号整数,位宽与平台相关类型并存
浮点f32、f64默认使用 f64
布尔bool取值为 true 或 false
字符char单个 Unicode 标量值
字符串String、&strString 可变且拥有所有权,&str 是字符串切片

Rust 支持显式标注类型,也支持通过上下文自动推导类型。初学时建议关键变量显式标注,方便阅读和排错。

使用建议:整数一般用于计数、索引和业务数值;浮点用于需要小数的计算;bool 用于状态分支;char 适合单字符处理;字符串场景中,如果只读展示优先用 &str,需要拼接或修改时使用 String。

rust
fn main() {
  let n: i32 = 42;
  let pi: f64 = 3.14;
  let ok: bool = true;
  let c: char = 'R';
  let s1: &str = "hello";
  let s2: String = String::from("rust");

  println!("{n} {pi} {ok} {c} {s1} {s2}");
}
rust
fn main() {
  let n = 42; // 推导为 i32
  let pi = 3.14; // 推导为 f64
  let ok = true; // bool
  let c = 'R'; // char
  let s1 = "hello"; // &str
  let s2 = String::from("rust"); // String

  println!("{n} {pi} {ok} {c} {s1} {s2}");
}
rust
// Rust 不做隐式数值转换,跨类型时需要显式转换,代码会更安全也更可控。
fn main() {
  let a: i32 = 10;
  let b: u64 = a as u64;

  let s: &str = "123";
  let n: i32 = s.parse().expect("parse i32 failed");

  println!("{b} {n}");
}

2. 复合类型

复合类型用于把多个值组织在一起。Rust 入门阶段最常见的是元组和数组。元组适合存放少量、类型可不同的数据;数组适合存放“同类型、固定长度”的数据。

2.1 元组(tuple)怎么用

元组的长度固定,但内部每个位置可以是不同类型。常见用法是函数返回多个值,或者把少量关联字段临时打包。

rust
fn main() {
  let user = ("zeming", 18, true);
  println!("name = {}, age = {}, active = {}", user.0, user.1, user.2);
}
rust
fn main() {
  let point = (3, 5);
  let (x, y) = point;
  println!("x = {x}, y = {y}");
}
2.2 数组(array)怎么用

数组要求元素类型一致且长度固定,适合已知大小的数据集合,比如固定配置、星期值、常量表等。访问数组时使用索引,从 0 开始。

rust
fn main() {
  let nums = [10, 20, 30, 40];
  let first = nums[0];
  println!("first = {first}");
}
rust
fn main() {
  let flags = [false; 5]; // [false, false, false, false, false]
  println!("{:?}", flags);
}
2.3 使用建议

如果你需要“不同类型的少量组合”,优先用元组;如果你需要“同类型且固定长度”的集合,优先用数组。
当集合长度需要动态变化时,不要用数组,应该切换到 Vec<T>(动态数组)。

三、流程控制

在 Rust 里,if、match、loop、while、for 都是高频工具。一个实用思路是:分支优先用 if/match,重复执行优先用 for/while/loop,再按场景补 break/continue。

1. 分支控制:if 与 match

if 适合条件较少的场景,而且它本身是表达式,可以直接返回值。
当分支较多、模式更明确时,match 通常可读性更好。

rust
fn main() {
  let is_vip = true;
  let discount = if is_vip { 20 } else { 5 };
  println!("discount = {discount}");

  let score = 88;
  let level = if score >= 90 { "A" } else if score >= 60 { "B" } else { "C" };
  println!("level = {level}");
}
rust
fn main() {
  let code = 2;
  let msg = match code {
    1 => "created",
    2 => "success",
    3 => "accepted",
    _ => "unknown",
  };
  println!("{msg}");
}

2. 循环控制:for、while、loop

for 适合遍历集合和区间;while 适合满足条件就继续;loop 适合需要手动控制退出时机的场景。在循环内部,continue 用于跳过本次迭代,break 用于直接结束循环。

rust
fn main() {
  for i in 0..5 {
    if i == 2 {
      continue; // 跳过 2
    }
    if i == 4 {
      break; // 提前结束
    }
    println!("{i}");
  }
}
rust
fn main() {
  let mut n = 2;
  while n > 0 {
    println!("while: {n}");
    n -= 1;
  }
}
rust
fn main() {
  let mut x = 0;
  let result = loop {
    x += 1;
    if x == 3 {
      break x * 10; // loop 可返回值
    }
  };
  println!("result = {result}");
}

什么时候用哪一个?简单真假判断用 if;离散枚举值或多模式分支用 match;已知遍历范围用 for;依赖条件反复执行用 while;需要自定义退出并返回值时用 loop

四、函数与返回值

参数与返回值类型需要显式标注。Rust 同时强调表达式风格,函数体最后一行如果没有分号,会被当作返回值。

rust
fn add(a: i32, b: i32) -> i32 {
  a + b // 表达式结尾无分号,表示返回值
}

fn main() {
  println!("{}", add(1, 2));
}

五、集合与常用结构

1. Vec、HashMap

当你需要“长度可变的同类型集合”时,用 Vec<T>;当你需要“键值映射”时,用 HashMap<K, V>。它们都存放在堆上,通常配合 mut 进行增删改。

rust
fn main() {
  let mut v = vec![1, 2, 3];
  v.push(4);

  let mut v = Vec::new();
  v.push(10);
  v.push(20);

  let first = v[0]; // 索引访问(越界会 panic)
  let maybe_second = v.get(1); // 安全访问,返回 Option<&T>

  println!("first = {first}, second = {:?}", maybe_second);

  for x in &v {
    println!("iter: {x}");
  }
}
rust
use std::collections::HashMap;

fn main() {
  let mut map: HashMap<String, i32> = HashMap::new();

  map.insert("a".to_string(), 1);
  map.insert("b".to_string(), 2);

  let a = map.get("a"); // Option<&i32>
  println!("a = {:?}", a);

  // entry:不存在则插入默认值,再进行累加等操作
  let count = map.entry("a".to_string()).or_insert(0);
  *count += 1;

  for (k, v) in &map {
    println!("{k} => {v}");
  }
}

六、结构体与枚举

结构体(struct)用来组织字段,适合表示“一个实体有哪些属性”;枚举(enum)用来表示“一个值只能是若干种情况之一”。
它们通常搭配 impl 写方法,并用 match 做分支处理。

rust
struct User {
  name: String,
  age: u8,
}

impl User {
  fn new(name: &str, age: u8) -> Self {
    Self { name: name.to_string(), age }
  }

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

fn main() {
  let u = User::new("Alice", 20);
  println!("{} adult? {}", u.name, u.is_adult());
}
rust
enum Status {
  Online,
  Offline,
}

fn main() {
  let s = Status::Online;
  match s {
    Status::Online => println!("online"),
    Status::Offline => println!("offline"),
  }
}

七、错误处理

Rust 更推荐用 Result<T, E> 表达“可能失败”的操作;panic! 适合真正不可恢复的错误(比如逻辑不变量被破坏)。
日常开发里,返回 Result 并用 ? 向上传播错误,是最常见的写法。

rust
fn divide(a: i32, b: i32) -> Result<i32, String> {
  if b == 0 {
    return Err("b cannot be 0".to_string());
  }
  Ok(a / b)
}

fn main() {
  match divide(10, 2) {
    Ok(v) => println!("ok: {v}"),
    Err(e) => println!("err: {e}"),
  }
}
rust
fn parse_and_double(s: &str) -> Result<i32, String> {
  let n: i32 = s.parse().map_err(|_| "parse failed".to_string())?;
  Ok(n * 2)
}

fn main() {
  let v = parse_and_double("21").unwrap();
  println!("{v}");
}

八、符号速查

这三个符号在 Rust 里出现频率很高,但含义完全不同:

:: 用于“路径与关联项”,常见在模块路径、类型路径、以及关联函数/关联常量(类似静态成员)的访问。
: 主要用于“标注/约束”,常见在变量类型标注、函数参数/返回值标注、trait 约束等。
. 用于“值上的操作”,常见在字段访问、方法调用、链式调用(在值或引用上工作)。

rust
use std::collections::HashMap;

struct User {
  name: String,
}

impl User {
  fn new(name: &str) -> Self {
    Self { name: name.to_string() }
  }
}

fn main() {
  let _m: HashMap<String, i32> = HashMap::new(); // 类型::关联函数
  let _u = User::new("Alice"); // 类型::关联函数
}
rust
fn add(a: i32, b: i32) -> i32 {
  a + b
}

fn main() {
  let x: u64 = 10; // 变量: 类型
  let _y = add(x as i32, 2);
}
rust
fn main() {
  let s = String::from("rust");

  let len = s.len(); // 方法调用
  let upper = s.to_uppercase().replace("RUST", "Rust"); // 链式调用

  println!("{len} {upper}");
}

小结

📖 相关资源

CC BY-NC-SA 4.0 协议