Rust 详细教程

Rust 是一种系统编程语言,专注于安全、并发和性能。以下是 Rust 的全面教程:

1. Rust 简介

主要特点

  • 内存安全:所有权系统保证内存安全
  • 零成本抽象:高级特性不带来运行时开销
  • 并发安全:借用检查器防止数据竞争
  • 高性能:与 C/C++ 相当的性能
  • 跨平台:支持多种操作系统和架构
  • 现代工具链:内置包管理器和构建工具

适用场景

  • 系统编程
  • 网络服务
  • 嵌入式开发
  • WebAssembly
  • 命令行工具
  • 高性能应用

2. Rust 安装

安装 Rust

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

更新 Rust

rustup update

验证安装

rustc --version
cargo --version

卸载 Rust

rustup self uninstall

3. 开发工具

1. Cargo (Rust 构建系统和包管理器)

cargo new project_name  # 创建新项目
cargo build             # 构建项目
cargo run               # 运行项目
cargo test              # 运行测试
cargo doc               # 生成文档
cargo update            # 更新依赖

2. 推荐 IDE/编辑器

  • VS Code + Rust Analyzer 插件
  • IntelliJ IDEA + Rust 插件
  • CLion + Rust 插件

4. 基本语法

Hello World

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

变量绑定

let x = 5;          // 不可变绑定
let mut y = 10;     // 可变绑定
const PI: f64 = 3.14159;  // 常量

数据类型

// 标量类型
let a: i32 = -42;       // 32位有符号整数
let b: u64 = 100;       // 64位无符号整数
let c: f64 = 3.14;      // 64位浮点数
let d: bool = true;     // 布尔值
let e: char = 'R';      // Unicode字符

// 复合类型
let tup: (i32, f64, char) = (500, 6.4, 'J');  // 元组
let arr: [i32; 5] = [1, 2, 3, 4, 5];           // 数组

控制流

// if 表达式
let number = 6;
if number % 4 == 0 {
    println!("divisible by 4");
} else if number % 3 == 0 {
    println!("divisible by 3");
} else {
    println!("not divisible by 4 or 3");
}

// 在 let 语句中使用 if
let condition = true;
let x = if condition { 5 } else { 6 };

// 循环
loop {
    println!("again!");
    break;
}

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

for element in [10, 20, 30].iter() {
    println!("value: {}", element);
}

for number in 1..4 {  // 范围
    println!("{}", number);
}

5. 所有权系统

所有权规则

  1. Rust 中每个值都有一个所有者
  2. 一次只能有一个所有者
  3. 当所有者离开作用域,值将被丢弃

移动语义

let s1 = String::from("hello");
let s2 = s1;  // s1 被移动到 s2
// println!("{}", s1);  // 错误!s1 不再有效

克隆

let s1 = String::from("hello");
let s2 = s1.clone();  // 深度拷贝
println!("s1 = {}, s2 = {}", s1, s2);  // 都有效

函数与所有权

fn takes_ownership(s: String) {
    println!("{}", s);
}  // s 离开作用域并被丢弃

let s = String::from("hello");
takes_ownership(s);
// println!("{}", s);  // 错误!s 已被移动

引用与借用

fn calculate_length(s: &String) -> usize {
    s.len()
}  // s 离开作用域但不会丢弃它指向的数据

let s = String::from("hello");
let len = calculate_length(&s);
println!("Length of '{}' is {}.", s, len);  // s 仍然有效

可变引用

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

let mut s = String::from("hello");
change(&mut s);

引用规则

  1. 任意时刻,只能有一个可变引用或多个不可变引用
  2. 引用必须总是有效的

6. 结构体

定义与实例化

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

let user1 = User {
    email: String::from("user@example.com"),
    username: String::from("someusername123"),
    active: true,
    sign_in_count: 1,
};

let mut user2 = User {
    email: String::from("another@example.com"),
    username: String::from("anotherusername567"),
    active: false,
    sign_in_count: 0,
};
user2.sign_in_count = 1;

元组结构体

struct Color(i32, i32, i32);
let black = Color(0, 0, 0);

方法语法

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }

    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }

    // 关联函数
    fn square(size: u32) -> Rectangle {
        Rectangle { width: size, height: size }
    }
}

7. 枚举与模式匹配

枚举

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

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

Option 枚举

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

let some_number = Some(5);
let absent_number: Option<i32> = None;

match 控制流

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState),
}

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => {
            println!("Lucky penny!");
            1
        }
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter(state) => {
            println!("State quarter from {:?}!", state);
            25
        }
    }
}

if let 简洁控制流

let some_u8_value = Some(3u8);
if let Some(3) = some_u8_value {
    println!("three");
}

8. 模块系统

模块定义

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

pub use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}

文件系统模块

src/
  lib.rs
  front_of_house/
    hosting.rs
// src/lib.rs
mod front_of_house;

pub use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}

// src/front_of_house/hosting.rs
pub fn add_to_waitlist() {}

9. 常见集合

Vector

let v: Vec<i32> = Vec::new();
let v = vec![1, 2, 3];

let third: &i32 = &v[2];
let third: Option<&i32> = v.get(2);

for i in &v {
    println!("{}", i);
}

let mut v = vec![100, 32, 57];
for i in &mut v {
    *i += 50;
}

String

let mut s = String::new();
let data = "initial contents";
let s = data.to_string();
let s = String::from("initial contents");

let mut s = String::from("foo");
s.push_str("bar");
s.push('!');

let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2;  // 注意 s1 被移动了

let s = format!("{}-{}-{}", "tic", "tac", "toe");

let hello = "Здравствуйте";
let s = &hello[0..4];  // 每个 Unicode 标量值占 2 字节

HashMap

use std::collections::HashMap;

let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);

let teams = vec![String::from("Blue"), String::from("Yellow")];
let initial_scores = vec![10, 50];
let scores: HashMap<_, _> = teams.iter().zip(initial_scores.iter()).collect();

let score = scores.get(&String::from("Blue"));

for (key, value) in &scores {
    println!("{}: {}", key, value);
}

scores.entry(String::from("Blue")).or_insert(50);

10. 错误处理

panic!

panic!("crash and burn");

Result

use std::fs::File;
use std::io::ErrorKind;

let f = File::open("hello.txt");

let f = match f {
    Ok(file) => file,
    Err(error) => match error.kind() {
        ErrorKind::NotFound => match File::create("hello.txt") {
            Ok(fc) => fc,
            Err(e) => panic!("Problem creating the file: {:?}", e),
        },
        other_error => {
            panic!("Problem opening the file: {:?}", other_error)
        }
    },
};

// 更简洁的写法
let f = File::open("hello.txt").unwrap_or_else(|error| {
    if error.kind() == ErrorKind::NotFound {
        File::create("hello.txt").unwrap_or_else(|error| {
            panic!("Problem creating the file: {:?}", error);
        })
    } else {
        panic!("Problem opening the file: {:?}", error);
    }
});

// unwrap 和 expect
let f = File::open("hello.txt").unwrap();
let f = File::open("hello.txt").expect("Failed to open hello.txt");

传播错误

use std::io;
use std::io::Read;
use std::fs::File;

fn read_username_from_file() -> Result<String, io::Error> {
    let mut f = File::open("hello.txt")?;
    let mut s = String::new();
    f.read_to_string(&mut s)?;
    Ok(s)
}

// 更简洁的写法
fn read_username_from_file() -> Result<String, io::Error> {
    let mut s = String::new();
    File::open("hello.txt")?.read_to_string(&mut s)?;
    Ok(s)
}

// 最简洁的写法
use std::fs;
fn read_username_from_file() -> Result<String, io::Error> {
    fs::read_to_string("hello.txt")
}

11. 泛型、Trait 和生命周期

泛型

fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
    let mut largest = list[0];
    for &item in list.iter() {
        if item > largest {
            largest = item;
        }
    }
    largest
}

struct Point<T> {
    x: T,
    y: T,
}

impl<T> Point<T> {
    fn x(&self) -> &T {
        &self.x
    }
}

Trait

pub trait Summary {
    fn summarize(&self) -> String {
        String::from("(Read more...)")
    }
}

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

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

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

// Trait Bound 语法
pub fn notify<T: Summary>(item: T) {
    println!("Breaking news! {}", item.summarize());
}

// 多个 Trait Bound
pub fn notify(item: impl Summary + Display) {}
pub fn notify<T: Summary + Display>(item: T) {}

// where 子句
fn some_function<T, U>(t: T, u: U) -> i32
    where T: Display + Clone,
          U: Clone + Debug
{}

// 返回实现了 Trait 的类型
fn returns_summarizable() -> impl Summary {
    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."),
    }
}

生命周期

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

struct ImportantExcerpt<'a> {
    part: &'a str,
}

impl<'a> ImportantExcerpt<'a> {
    fn level(&self) -> i32 {
        3
    }

    fn announce_and_return_part(&self, announcement: &str) -> &str {
        println!("Attention please: {}", announcement);
        self.part
    }
}

12. 测试

单元测试

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }

    #[test]
    fn larger_can_hold_smaller() {
        let larger = Rectangle { width: 8, height: 7 };
        let smaller = Rectangle { width: 5, height: 1 };
        assert!(larger.can_hold(&smaller));
    }

    #[test]
    #[should_panic(expected = "Guess value must be between 1 and 100")]
    fn greater_than_100() {
        Guess::new(200);
    }

    #[test]
    fn it_works() -> Result<(), String> {
        if 2 + 2 == 4 {
            Ok(())
        } else {
            Err(String::from("two plus two does not equal four"))
        }
    }
}

集成测试

tests/
  integration_test.rs
use adder;

#[test]
fn it_adds_two() {
    assert_eq!(4, adder::add_two(2));
}

13. 并发编程

线程

use std::thread;
use std::time::Duration;

let handle = thread::spawn(|| {
    for i in 1..10 {
        println!("hi number {} from the spawned thread!", i);
        thread::sleep(Duration::from_millis(1));
    }
});

for i in 1..5 {
    println!("hi number {} from the main thread!", i);
    thread::sleep(Duration::from_millis(1));
}

handle.join().unwrap();

消息传递

use std::sync::mpsc;
use std::thread;

let (tx, rx) = mpsc::channel();

thread::spawn(move || {
    let val = String::from("hi");
    tx.send(val).unwrap();
});

let received = rx.recv().unwrap();
println!("Got: {}", received);

共享状态

use std::sync::{Mutex, Arc};
use std::thread;

let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];

for _ in 0..10 {
    let counter = Arc::clone(&counter);
    let handle = thread::spawn(move || {
        let mut num = counter.lock().unwrap();
        *num += 1;
    });
    handles.push(handle);
}

for handle in handles {
    handle.join().unwrap();
}

println!("Result: {}", *counter.lock().unwrap());

14. 面向对象编程

结构体与方法

pub struct AveragedCollection {
    list: Vec<i32>,
    average: f64,
}

impl AveragedCollection {
    pub fn add(&mut self, value: i32) {
        self.list.push(value);
        self.update_average();
    }

    pub fn remove(&mut self) -> Option<i32> {
        let result = self.list.pop();
        match result {
            Some(value) => {
                self.update_average();
                Some(value)
            }
            None => None,
        }
    }

    pub fn average(&self) -> f64 {
        self.average
    }

    fn update_average(&mut self) {
        let total: i32 = self.list.iter().sum();
        self.average = total as f64 / self.list.len() as f64;
    }
}

Trait 对象

pub trait Draw {
    fn draw(&self);
}

pub struct Screen {
    pub components: Vec<Box<dyn Draw>>,
}

impl Screen {
    pub fn run(&self) {
        for component in self.components.iter() {
            component.draw();
        }
    }
}

15. 高级特性

不安全 Rust

unsafe fn dangerous() {}

unsafe {
    dangerous();
}

// 解引用裸指针
let mut num = 5;
let r1 = &num as *const i32;
let r2 = &mut num as *mut i32;

unsafe {
    println!("r1 is: {}", *r1);
    *r2 = 10;
}

// 调用不安全函数
extern "C" {
    fn abs(input: i32) -> i32;
}

unsafe {
    println!("Absolute value of -3 according to C: {}", abs(-3));
}

高级 Trait

use std::ops::Add;

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

impl Add for Point {
    type Output = Point;

    fn add(self, other: Point) -> Point {
        Point {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}

trait Pilot {
    fn fly(&self);
}

trait Wizard {
    fn fly(&self);
}

struct Human;

impl Pilot for Human {
    fn fly(&self) {
        println!("This is your captain speaking.");
    }
}

impl Wizard for Human {
    fn fly(&self) {
        println!("Up!");
    }
}

impl Human {
    fn fly(&self) {
        println!("*waving arms furiously*");
    }
}

let person = Human;
Pilot::fly(&person);
Wizard::fly(&person);
person.fly();

高级类型

type Kilometers = i32;

let x: i32 = 5;
let y: Kilometers = 5;
println!("x + y = {}", x + y);

// Never 类型 (!)
fn bar() -> ! {
    loop {
        println!("forever");
    }
}

// 声明宏
#[macro_export]
macro_rules! vec {
    ( $( $x:expr ),* ) => {
        {
            let mut temp_vec = Vec::new();
            $(
                temp_vec.push($x);
            )*
            temp_vec
        }
    };
}

// 使用宏
let v: Vec<u32> = vec![1, 2, 3];

// 过程宏
use hello_macro::HelloMacro;
use hello_macro_derive::HelloMacro;

#[derive(HelloMacro)]
struct Pancakes;

fn main() {
    Pancakes::hello_macro();
}

16. 实战项目

1. 命令行工具

use std::env;
use std::process;

fn main() {
    let args: Vec<String> = env::args().collect();

    let config = Config::new(&args).unwrap_or_else(|err| {
        println!("Problem parsing arguments: {}", err);
        process::exit(1);
    });

    if let Err(e) = minigrep::run(config) {
        println!("Application error: {}", e);
        process::exit(1);
    }
}

2. Web 服务器

use std::io::prelude::*;
use std::net::TcpListener;
use std::net::TcpStream;

fn main() {
    let listener = TcpListener::bind("127.0.0.1:7878").unwrap();

    for stream in listener.incoming() {
        let stream = stream.unwrap();
        handle_connection(stream);
    }
}

fn handle_connection(mut stream: TcpStream) {
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).unwrap();

    let get = b"GET / HTTP/1.1\r\n";

    let (status_line, contents) = if buffer.starts_with(get) {
        ("HTTP/1.1 200 OK", "Hello, World!")
    } else {
        ("HTTP/1.1 404 NOT FOUND", "404 Not Found")
    };

    let response = format!(
        "{}\r\nContent-Length: {}\r\n\r\n{}",
        status_line,
        contents.len(),
        contents
    );

    stream.write(response.as_bytes()).unwrap();
    stream.flush().unwrap();
}

3. 多线程 Web 服务器

use std::thread;
use std::sync::mpsc;
use std::sync::Arc;
use std::sync::Mutex;

type Job = Box<dyn FnOnce() + Send + 'static>;

struct Worker {
    id: usize,
    thread: Option<thread::JoinHandle<()>>,
}

impl Worker {
    fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Job>>>) -> Worker {
        let thread = thread::spawn(move || loop {
            let job = receiver.lock().unwrap().recv().unwrap();
            println!("Worker {} got a job; executing.", id);
            job();
        });

        Worker {
            id,
            thread: Some(thread),
        }
    }
}

pub struct ThreadPool {
    workers: Vec<Worker>,
    sender: mpsc::Sender<Job>,
}

impl ThreadPool {
    pub fn new(size: usize) -> ThreadPool {
        assert!(size > 0);

        let (sender, receiver) = mpsc::channel();
        let receiver = Arc::new(Mutex::new(receiver));

        let mut workers = Vec::with_capacity(size);

        for id in 0..size {
            workers.push(Worker::new(id, Arc::clone(&receiver)));
        }

        ThreadPool { workers, sender }
    }

    pub fn execute<F>(&self, f: F)
    where
        F: FnOnce() + Send + 'static,
    {
        let job = Box::new(f);
        self.sender.send(job).unwrap();
    }
}

Rust 是一门强大而复杂的语言,本教程涵盖了 Rust 的主要特性和概念。要精通 Rust 需要大量实践,建议通过实际项目来巩固所学知识。









results matching ""

    No results matching ""