Rust模式匹配、所有权与借用

目录所有权与借用所有权引用与借用流程控制模式匹配match和iflet解构Option模式适用场景全模式列表方法method所有权与借用所有权(Ownership)所有权机制是Rust中管理内存的核心方式。每个值都有一个所有者,而且任何时候只能有一个

目录


所有权与借用

所有权 (Ownership)

所有权机制是 Rust 中管理内存的核心方式。每个值都有一个所有者,而且任何时候只能有一个所有者。当所有者离开作用域时,该值会被自动清理。

基本所有权规则

  • 每个值都有一个所有者。
  • 只有当所有者离开作用域时,值才会被清理。

所有权转移 当你将一个值赋给另一个变量时,原来的变量将不再拥有该值。

示例代码:

fn main() {
    let s1 = String::from("hello");
    let s2 = s1; // 所有权转移

    println!("{}", s2); // 输出 "hello"
    // println!("{}", s1); // 编译错误:s1 已经不再有效
}

借用 (Borrowing)

借用允许你在不改变所有权的情况下访问值。Rust 有两种类型的借用:不可变借用和可变借用。

不可变借用 不可变借用允许你读取但不能修改值。

fn main() {
    let s = String::from("hello");

    let len = calculate_length(&s); // 不可变借用

    println!("The length of '{}' is {}.", s, len);
}

fn calculate_length(s: &String) -> usize {
    s.len()
}

可变借用 可变借用允许你修改值,但同一时间内只能有一个可变借用。

fn main() {
    let mut s = String::from("hello");

    change(&mut s); // 可变借用

    println!("{}", s); // 输出 "hello world"
}

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

借用规则 在同一时间内,只能有一个可变借用或者任意数量的不可变借用。 借用必须在有效的作用域内。

生命周期 (Lifetimes)

生命周期确保引用不会超出其所有者的生命周期。生命周期注解用于明确指明引用的有效范围。

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

fn main() {
    let string1 = String::from("long string is long");
    let string2 = String::from("xyz");

    let result = longest(string1.as_str(), string2.as_str());
    println!("The longest string is {}", result);
}

综合示例:所有权与借用

下面是一个综合示例,展示了所有权和借用在实际应用中的使用。

示例代码:字符串处理

fn main() {
    let mut s = String::from("hello");

    // 不可变借用
    let len = calculate_length(&s);
    println!("Length: {}", len);

    // 可变借用
    change(&mut s);
    println!("After change: {}", s);

    // 使用生命周期注解
    let result = longest_with_lifetime(&s, "world");
    println!("Longest: {}", result);
}

fn calculate_length(s: &String) -> usize {
    s.len()
}

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

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

流程控制

条件语句

使用 ifelse 进行条件判断。

示例代码:

fn main() {
    let number = 5;

    if number % 2 == 0 {
        println!("number is even");
    } else {
        println!("number is odd");
    }
}

循环语句

  • while 循环
  • for 循环
fn main() {
    let mut count = 0;

    while count < 5 {
        println!("count is {}", count);
        count += 1;
    }

    for i in 0..5 {
        println!("i is {}", i);
    }
}

模式匹配

模式匹配是 Rust 中的一个强大特性,它可以让你以一种简洁且安全的方式处理数据结构。

match 语句

match 语句允许你根据不同的模式执行不同的代码块。

基本语法

let some_value = 1;

match some_value {
    1 => println!("One"),
    2 => println!("Two"),
    _ => println!("Anything else"),
}

解构 Option<T>

Option&lt;T> 是 Rust 中常用的类型,表示可能为空的值。

fn main() {
    let some_option = Some(5);
    let none_option: Option&lt;i32> = None;

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

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

解构元组

match 语句可以解构元组。

fn main() {
    let point = (1, 2);

    match point {
        (x, y) => println!("Point: ({}, {})", x, y),
    }
}

解构枚举

枚举也可以通过 match 语句进行解构。

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

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

    match msg {
        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!("Change color to ({}, {}, {})", r, g, b),
    }
}

if let 语句

if let 语句是一种更简洁的方式来匹配单个模式。

解构 Option<T>

fn main() {
    let some_option = Some(5);
    let none_option: Option&lt;i32> = None;

    if let Some(value) = some_option {
        println!("Some value: {}", value);
    } else {
        println!("No value");
    }

    if let Some(value) = none_option {
        println!("Some value: {}", value);
    } else {
        println!("No value");
    }
}

解构元组

fn main() {
    let point = (1, 2);

    if let (x, y) = point {
        println!("Point: ({}, {})", x, y);
    }
}

解构枚举

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

    if let Message::Write(text) = msg {
        println!("Write: {}", text);
    }
}

模式适用场景

处理 Option<T>

fn main() {
    let some_option = Some(5);
    let none_option: Option&lt;i32> = None;

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

    if let Some(value) = none_option {
        println!("Some value: {}", value);
    } else {
        println!("No value");
    }
}

处理 Result<T, E>

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

fn read_username_from_file(filename: &str) -> Result&lt;String, io::Error> {
    let mut file = File::open(filename)?;
    let mut username = String::new();
    file.read_to_string(&mut username)?;
    Ok(username)
}

fn main() {
    let filename = "username.txt";

    match read_username_from_file(filename) {
        Ok(username) => println!("Username: {}", username),
        Err(e) => println!("Error reading file: {}", e),
    }

    if let Ok(username) = read_username_from_file(filename) {
        println!("Username: {}", username);
    } else {
        println!("Error reading file");
    }
}

处理枚举

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

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

    match msg {
        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!("Change color to ({}, {}, {})", r, g, b),
    }

    if let Message::Write(text) = msg {
        println!("Write: {}", text);
    }
}

匹配常量

let num = 5;

match num {
    5 => println!("Five"),
    _ => println!("Not five"),
}

匹配变量

let num = 5;

match num {
    x if x > 0 => println!("Positive: {}", x),
    _ => println!("Not positive"),
}

匹配元组

fn main() {
    let point = (3, 4);

    match point {
        (0, 0) => println!("origin"),
        (0, y) => println!("on the y-axis with y = {}", y),
        (x, 0) => println!("on the x-axis with x = {}", x),
        (x, y) => println!("on neither axis: ({}, {})", x, y),
    }
}

匹配枚举

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

fn main() {
    let m = Message::Write(String::from("hello"));

    match m {
        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!("change color to ({}, {}, {})", r, g, b),
    }
}

匹配结构体

struct Point {
    x: i32,
    y: i32,
}

impl Point {
    fn new(x: i32, y: i32) -> Point {
        Point { x, y }
    }
}

fn main() {
    let p = Point::new(3, 4);

    match p {
        Point { x, y } => println!("point at ({}, {})", x, y),
    }
}

方法method

方法是与特定类型关联的函数,可以访问该类型的实例。

定义方法

struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn new(width: u32, height: u32) -> Rectangle {
        Rectangle { width, height }
    }

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

    fn perimeter(&self) -> u32 {
        2 * (self.width + self.height)
    }
}

fn main() {
    let rect = Rectangle::new(10, 20);

    println!("area is {}", rect.area());      // 输出 200
    println!("perimeter is {}", rect.perimeter()); // 输出 60
}

方法的参数

方法可以有多种不同的参数形式,包括引用、可变引用等。

struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn new(width: u32, height: u32) -> Rectangle {
        Rectangle { width, height }
    }

    fn set_width(&mut self, new_width: u32) {
        self.width = new_width;
    }

    fn get_width(&self) -> u32 {
        self.width
    }
}

fn main() {
    let mut rect = Rectangle::new(10, 20);

    println!("initial width is {}", rect.get_width()); // 输出 10

    rect.set_width(15);
    println!("new width is {}", rect.get_width());     // 输出 15
}

实战示例

让我们通过一个更复杂的示例来综合运用这些概念。

示例代码:实现一个简单的计算器

enum Operation {
    Add,
    Subtract,
    Multiply,
    Divide,
}

struct Calculator {
    current_value: f64,
}

impl Calculator {
    fn new() -> Calculator {
        Calculator { current_value: 0.0 }
    }

    fn perform_operation(&mut self, operation: Operation, value: f64) {
        match operation {
            Operation::Add => self.current_value += value,
            Operation::Subtract => self.current_value -= value,
            Operation::Multiply => self.current_value *= value,
            Operation::Divide => {
                if value != 0.0 {
                    self.current_value /= value;
                } else {
                    println!("Cannot divide by zero");
                }
            }
        }
    }

    fn get_current_value(&self) -> f64 {
        self.current_value
    }
}

fn main() {
    let mut calculator = Calculator::new();

    calculator.perform_operation(Operation::Add, 5.0);
    calculator.perform_operation(Operation::Multiply, 2.0);
    calculator.perform_operation(Operation::Subtract, 3.0);
    calculator.perform_operation(Operation::Divide, 2.0);

    println!("Current value: {}", calculator.get_current_value());
}

详细分析

枚举 Operation

enum Operation {
    Add,
    Subtract,
    Multiply,
    Divide,
}
  • 定义:枚举 Operation 定义了四种不同的操作:加法、减法、乘法和除法。
  • 使用:通过枚举可以方便地表示不同的操作类型,并且在模式匹配中进行区分。

结构体 Calculator

struct Calculator {
    current_value: f64,
}
  • 定义:结构体 Calculator 有一个字段 current_value,用于存储当前计算的结果。
  • 初始化:通过 new 方法创建一个新的 Calculator 实例,初始值为 0.0。

实现 Calculator

impl Calculator {
    fn new() -> Calculator {
        Calculator { current_value: 0.0 }
    }

    fn perform_operation(&mut self, operation: Operation, value: f64) {
        match operation {
            Operation::Add => self.current_value += value,
            Operation::Subtract => self.current_value -= value,
            Operation::Multiply => self.current_value *= value,
            Operation::Divide => {
                if value != 0.0 {
                    self.current_value /= value;
                } else {
                    println!("Cannot divide by zero");
                }
            }
        }
    }

    fn get_current_value(&self) -> f64 {
        self.current_value
    }
}
  • new 方法:创建一个新的 Calculator 实例。
  • perform_operation 方法:执行指定的操作并更新 current_value。
  • 模式匹配:根据传入的 operation 枚举值执行相应的操作。
  • 除法特殊处理:如果除数为零,则打印错误信息而不执行除法操作。
  • get_current_value 方法:返回当前的计算结果。

主函数 main

fn main() {
    let mut calculator = Calculator::new();

    calculator.perform_operation(Operation::Add, 5.0);
    calculator.perform_operation(Operation::Multiply, 2.0);
    calculator.perform_operation(Operation::Subtract, 3.0);
    calculator.perform_operation(Operation::Divide, 2.0);

    println!("Current value: {}", calculator.get_current_value());
}
  • 初始化:创建一个新的 Calculator 实例。
  • 执行操作:依次执行加法、乘法、减法和除法操作。
  • 输出结果:打印最终的计算结果。
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
天涯学馆
天涯学馆
0x9d6d...50d5
资深大厂程序员,12年开发经验,致力于探索前沿技术!