跳转至

Rust 入门实战

Rust 是一门强调安全性和性能的系统编程语言,通过所有权机制在编译时消除内存错误,不需要垃圾回收就能保证内存安全,是编写高性能生信工具的理想选择。

核心知识点

知识点说明
语言类型系统编程语言,编译型
最新版本Rust 1.90+(2024 Edition)
核心优势内存安全(无 GC)、高性能、零成本抽象
包管理器Cargo(构建 + 依赖管理 + 测试)
适用场景CLI 工具、高性能计算、WebAssembly、系统工具
生信应用很多新一代生信工具用 Rust 写(如 nf-core 组件)
学习资源"The Book"(官方教程)、Rustlings(练习题)

安装配置

# 安装 Rust 工具链(rustup)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh  # 安装 rustup
source $HOME/.cargo/env  # 加载环境变量

# 验证安装
rustc --version           # Rust 编译器版本
cargo --version           # Cargo 包管理器版本

# 更新 Rust
rustup update             # 更新到最新版本

# 安装常用组件
rustup component add rustfmt   # 代码格式化工具
rustup component add clippy    # 代码检查工具

基本使用

1. 创建项目

cargo new hello_rust      # 创建新项目
cd hello_rust              # 进入项目目录
cargo run                  # 编译并运行

2. 基本语法

// src/main.rs

fn main() {
    // 变量(默认不可变)
    let name = "Rust";                    // 不可变变量
    let mut count = 0;                    // 可变变量(mut 关键字)
    count += 1;

    // 数据类型
    let age: u32 = 25;                    // 无符号 32 位整数
    let bmi: f64 = 28.5;                  // 64 位浮点数
    let is_healthy: bool = false;         // 布尔值
    let sample_id: &str = "T2D_001";      // 字符串切片

    // 打印
    println!("Hello, {}!", name);         // 格式化打印
    println!("BMI: {:.2}", bmi);          // 保留两位小数

    // if 表达式
    let status = if bmi > 25.0 {          // if 是表达式,有返回值
        "overweight"
    } else {
        "normal"
    };

    // 循环
    for i in 0..5 {                       // 范围循环 0,1,2,3,4
        println!("第 {} 次", i);
    }

    // 向量(动态数组)
    let mut scores: Vec<f64> = vec![8.5, 9.0, 7.5];  // 创建向量
    scores.push(8.0);                     // 添加元素
    let avg: f64 = scores.iter().sum::<f64>() / scores.len() as f64;  // 计算平均值
    println!("平均分: {:.1}", avg);
}

3. 所有权系统(Rust 核心概念)

fn main() {
    // 所有权规则:
    // 1. 每个值有且只有一个所有者
    // 2. 同一时间只能有一个所有者
    // 3. 所有者离开作用域,值被释放

    let s1 = String::from("hello");       // s1 拥有这个字符串
    let s2 = s1;                          // 所有权转移给 s2,s1 不再可用
    // println!("{}", s1);                // 编译错误!s1 已经失效

    // 借用(引用)—— 不转移所有权
    let s3 = String::from("world");
    let len = calculate_length(&s3);      // & 表示借用,不转移所有权
    println!("长度: {}, 内容: {}", len, s3);  // s3 仍然可用

    // 可变借用
    let mut s4 = String::from("hello");
    change(&mut s4);                      // &mut 可变借用
    println!("{}", s4);                   // 输出 "hello, world"
}

fn calculate_length(s: &String) -> usize {  // 接受引用,不获取所有权
    s.len()
}

fn change(s: &mut String) {               // 接受可变引用
    s.push_str(", world");
}

4. 结构体和枚举

// 定义结构体
struct Sample {
    id: String,                           // 样本 ID
    diagnosis: String,                    // 诊断
    bmi: f64,                             // BMI
}

impl Sample {                            // 为结构体实现方法
    fn new(id: &str, diagnosis: &str, bmi: f64) -> Self {  // 构造函数
        Sample {
            id: id.to_string(),
            diagnosis: diagnosis.to_string(),
            bmi,
        }
    }

    fn is_overweight(&self) -> bool {     // 方法
        self.bmi > 25.0
    }
}

// 枚举(Rust 的枚举非常强大)
enum DiagnosisGroup {
    T2D,
    Healthy,
    Unknown(String),                      // 可以携带数据
}

fn main() {
    let s = Sample::new("T2D_001", "T2D", 28.5);
    println!("{} 超重: {}", s.id, s.is_overweight());

    // 模式匹配(match)
    let group = DiagnosisGroup::T2D;
    match group {
        DiagnosisGroup::T2D => println!("2型糖尿病"),
        DiagnosisGroup::Healthy => println!("健康对照"),
        DiagnosisGroup::Unknown(msg) => println!("未知: {}", msg),
    }
}

高级用法

1. 错误处理(Result 类型)

use std::fs;                              // 文件系统模块
use std::io;

fn read_sample_data(path: &str) -> Result<String, io::Error> {
    let content = fs::read_to_string(path)?;  // ? 操作符:出错则返回错误
    Ok(content)                           // 成功返回内容
}

fn main() {
    match read_sample_data("data.txt") {
        Ok(data) => println!("读取成功: {} 字节", data.len()),
        Err(e) => eprintln!("读取失败: {}", e),
    }
}

2. 命令行工具(使用 clap)

# Cargo.toml 添加依赖
[dependencies]
clap = { version = "4", features = ["derive"] }
use clap::Parser;                         // 导入 clap 的 Parser

#[derive(Parser)]
#[command(name = "bmi_calc", about = "BMI 计算器")]
struct Args {
    #[arg(short, long)]
    weight: f64,                          // 体重(kg)
    #[arg(short = 'H', long)]
    height: f64,                          // 身高(m)
}

fn main() {
    let args = Args::parse();             // 自动解析命令行参数
    let bmi = args.weight / (args.height * args.height);
    println!("BMI: {:.1}", bmi);
}
// 运行: cargo run -- --weight 75 --height 1.75

3. 文件读写(处理 TSV/CSV)

use std::fs::File;
use std::io::{BufRead, BufReader, Write};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 读取 TSV 文件
    let file = File::open("abundance.tsv")?;
    let reader = BufReader::new(file);

    for line in reader.lines() {
        let line = line?;
        let fields: Vec<&str> = line.split('\t').collect();  // 按 tab 分割
        if fields.len() >= 2 {
            println!("样本: {}, 丰度: {}", fields[0], fields[1]);
        }
    }

    // 写入文件
    let mut output = File::create("output.tsv")?;
    writeln!(output, "sample\tbmi\tgroup")?;
    writeln!(output, "T2D_001\t28.5\tcase")?;

    Ok(())
}

常见报错与解决

报错信息原因解决方法
value used after move所有权已转移使用 .clone() 或借用 &
cannot borrow as mutable不可变变量尝试修改mut 关键字
lifetime error生命周期不匹配添加生命周期标注或重构
type mismatch类型不匹配使用 as 转换或 into()
unresolved import依赖未添加在 Cargo.toml 中添加依赖

速查表

// ===== Rust 速查表 =====

// 变量
let x = 5;                   // 不可变
let mut y = 10;               // 可变
let z: f64 = 3.14;            // 指定类型

// 函数
fn add(a: i32, b: i32) -> i32 { a + b }

// 控制流
if x > 0 { } else { }
for i in 0..10 { }
while x > 0 { }
loop { break; }

// 集合
let v = vec![1, 2, 3];        // 向量
let mut m = HashMap::new();   // 哈希表

// 错误处理
let r: Result<T, E> = Ok(val);
let o: Option<T> = Some(val);
let val = result?;             // 传播错误

// Cargo 命令
// cargo new project      创建项目
// cargo build             编译
// cargo run               编译运行
// cargo test              运行测试
// cargo fmt               格式化代码
// cargo clippy            代码检查
// cargo add dep           添加依赖