Rust新特性学习笔记(还有忘了的东西嘻嘻)

星期五, 11月 29, 2024 | 3分钟阅读 | 更新于 星期四, 1月 9, 2025

妈的,Rust怎么迭代这么快啊。。。。

标签系统

不知道这是啥时候出来的特性,可以在循环内使用,可以直接break

fn main() {
    let s = [[5, 6, 7], [8, 9, 10], [21, 15, 32]];
    let mut elements_searched = 0;
    let target_value = 10;
    'outer: for i in [0, 1, 2] {
        for j in 0..=2 {
            elements_searched += 1;
            if s[i][j] == target_value {
                break 'outer;
            }
        }
    }
    print!("elements searched: {elements_searched}");
}

代码块

抽象的东西,奶奶的。用大括号括起来的叫做代码块。每个块有valuetype

let x = { // 这是一个代码块
        let y = 10;
        println!("y: {y}");
        z - y //最后一个数值被赋予给x
    };

作用域

Rust安全的原因就是这个,变量拥有作用域,也就是变量只作用于一个封闭的代码空间。

fn main() {
    let a = 10;
    println!("before: {a}");
    {
        let a = "hello";
        println!("inner scope: {a}");

        let a = true;
        println!("shadowed in inner scope: {a}");
    }

    println!("after: {a}");//最先的变量a的作用域包含整个大的代码块,它不会被小的代码块遮蔽,所以最后的print仍为10
}

现在函数返回值不需要使用return也可以

fn gcd(a: u32, b: u32) -> u32 {
    if b > 0 {
        gcd(b, a % b)
    } else {
        a
    }
}

Rust常用的宏

  1. println!

    标准输出,自带换行,不换行使用print!

  2. format!

    字符串形式输出

  3. dbg!

    记录某个值然后输出,用在debug

  4. todo!

    标记未实现的代码区域,运行会panic

  5. unreachable!

    无法访问的代码区域,运行会panic

Rust数组和元祖

  1. Rust的数组可以使用美观打印以保证数组易读性,使用{:?}
  2. 元组将多种类型的值组合成复合类型,使用()包裹。

Rust模式匹配

  1. 模式匹配使用match 变量 {},与switch类似
  2. 可以在代码块中定义一些判断,如key if key.is_lowercase() => println!("Lowercase: {key}")
  3. _为模式匹配的通配符,负责显示所有情况

解构

  1. 解构就是把复合类型分解成组成部分的过程
  2. 解构一般使用模式匹配实现
  3. 解构结构体:
struct Foo {
    x: (u32, u32), //定义元组
    y: u32,
}

#[rustfmt::skip] //跳过格式化的宏
fn main() {
    let foo = Foo { x: (1, 2), y: 3 };
    match foo {
        Foo { x: (1, b), y } => println!("x.0 = 1, b = {b}, y = {y}"),//匹配x元组第一个元素为1,则把第二个元素赋给b,把y字段赋值给y
        Foo { y: 2, x: i }   => println!("y = 2, x = {i:?}"),//与上部分类似
        Foo { y, .. }        => println!("y = {y}, other fields were ignored"),//`..`表示忽略其他情况
    }
}

let控制流

  1. 除了match,还可以使用let表达式实现模式匹配,以及解构
  2. if let表达式:
use std::time::Duration;

fn sleep_for(secs: f32) {
    if let Ok(dur) = Duration::try_from_secs_f32(secs) {
        std::thread::sleep(dur);
        println!("slept for {:?}", dur);
    }
}

fn main() {
    sleep_for(-10.0);
    sleep_for(0.8);
}
  1. let else表达式
fn hex_or_die_trying(maybe_string: Option<String>) -> Result<u32, String> {
    let s = if let Some(s) = maybe_string {
        s
    } else {
        return Err(String::from("got None"));
    };

    let first_byte_char = if let Some(first_byte_char) = s.chars().next() {
        first_byte_char
    } else {
        return Err(String::from("got empty string"));
    };

    if let Some(digit) = first_byte_char.to_digit(16) {
        Ok(digit)
    } else {
        Err(String::from("not a hex digit"))
    }
}

fn main() {
    println!("result: {:?}", hex_or_die_trying(Some(String::from("foo"))));
}

重要

如需了解匹配模式并从函数返回的常见情况,请使用 let else。“else” 分支必须执行不同的结束方式(例如,return、break 或 panic,但不能直接执行到代码块的末尾)。

  1. while let表达式 while let与if let类似,只是会重复测试一个值
fn main() {
    let mut name = String::from("Comprehensive Rust 🦀");
    while let Some(c) = name.pop() {
        println!("character: {c}");
    }
}

方法和特征

  1. 方法 Rust允许将函数与新类型相关联,使用impl包裹,例子如下:
#[derive(Debug)]
struct Race {
    name: String,
    laps: Vec<i32>, //动态数组存圈数
}

impl Race {
    // 静态方法
    fn new(name: &str) -> Self {
        Self {
            name: String::from(name),
            laps: Vec::new(),
        }
    }

    // 可变借用,修改结构体
    fn add_lap(&mut self, lap: i32) {
        self.laps.push(lap);
    }

    // 不可变借用,只读访问
    fn print_laps(&self) {
        println!("Recorded {} laps for {}:", self.laps.len(), self.name);
        for (idx, lap) in self.laps.iter().enumerate() {
            println!("Lap {idx}: {lap} sec");
        }
    }

    // 获取所有权,消耗实例
    fn finish(self) {
        let total: i32 = self.laps.iter().sum();
        println!("Race {} is finished, total lap time: {}", self.name, total);
    }
}

fn main() {
    let mut race = Race::new("Monaco Grand Prix");
    race.add_lap(70);
    race.add_lap(68);
    race.print_laps();
    race.add_lap(71);
    race.print_laps();
    race.finish();
    // race.add_lap(42);//已被finish消耗了,再调用会编译错误
}

self参数指定receiver - 该方法作用的对象。方法有几种常见的receiver:

  • &self:使用不可变的共享引用从调用方借用对象。之后可以再次使用该对象。
  • &mut self:使用唯一的可变引用从调用方借用对象。之后可以再次使用该对象。
  • self:获取对象的所有权并将其从调用方移出。该方法会成为对象的所有者。除非明确转移对象的所有权,否则在该方法返回时,对象将被丢弃(取消分配)。具备完全所有权,不自动等同于具备可变性。
  • mut self:同上,但该方法可以改变对象。
  • 无receiver:这将变为结构体上的静态方法。通常用于创建构造函数,按惯例被称为new

实现结果:

Recorded 2 laps for Monaco Grand Prix:
Lap 0: 70 sec
Lap 1: 68 sec
Recorded 3 laps for Monaco Grand Prix:
Lap 0: 70 sec
Lap 1: 68 sec
Lap 2: 71 sec
Race Monaco Grand Prix is finished, total lap time: 209

© 2024 - 2025 Aiser's Blog

欢迎来到我的博客!

Me

我的名字是Aiser,这是我的博客