⚙️ Rust

泛型

在 Rust 中,泛型提供了一种用于编写函数、结构体、枚举和定义通用代码的方法。这样可以在不同类型上复用逻辑,提高代码的灵活性和可重用性。以下是泛型的核心概念和使用方法。 泛型函数 泛型函数允许你编写对多种类型都适用的函数。泛型参数通常采用大写字母: fn largest<T: PartialOrd>(list: &[T]) -> &T { let mut largest = &list[0]; for item in list.iter() { if item > largest { largest = item; } } largest } fn main() { let numbers = vec![1, 2, 3, 4, 5]; println!("The largest number is {}", largest(&numbers)); } 泛型结构体 结构体也可以使用泛型来定义其字段的类型: struct Point<T> { x: T, y: T, } fn main() { let integer_point = Point { x: 5, y: 10 }; let float_point = Point { x: 1.

更多 →

September 23, 2024

常见错误集锦

Value used after being moved [E0382] 在Rust中,错误 E0382 表示你尝试使用一个已经被移动(moved)的值。在Rust里,当一个值被移动到另一个变量时,原来的变量就不能再被使用了,因为它的所有权(ownership)已经转移。这是Rust独特的所有权系统的一部分,旨在防止数据竞争和无效引用。 这个错误通常发生在以下情况: 当一个非Copy类型的值被赋值给另一个变量时。 当一个值被作为参数传递给函数时,这个值的所有权被转移给了函数的参数。 下面是一个具体的示例,展示了如何触发这个错误: fn take_ownership(s: String) { println!("I own the String: {}", s); } fn main() { let s1 = String::from("hello"); take_ownership(s1); // `s1` 的所有权被移动到函数 `take_ownership` println!("Can I use s1? {}", s1); // 错误!尝试使用已经被移动的值 `s1` } 在这个例子中,s1 是一个String类型的值,它不是Copy类型。当我们调用take_ownership(s1)时,s1的所有权被移动到函数参数s中。在这之后,s1就不能再被使用了,因为它已经不再拥有那个String值。尝试在take_ownership函数调用之后打印s1会导致编译器报错 E0382。 要解决这个问题,你可以选择: 不在take_ownership之后使用s1。 使用引用传递,这样所有权不会被移动。 如果类型实现了Clone trait,可以克隆(clone)s1并传递克隆的值。 temporary value dropped while borrowed [E0716] error[E0716]: temporary value dropped while borrowed --> lattice/src/builder.rs:94:26 | 94 | let sk = HexString::new("0x00a50da54a1987bf5ddd773e9c151bd40aa5d1281b8936dbdec93a9d0a04e4ca").

更多 →

June 19, 2024

trait

1.trait 在 Rust 中,trait 是一种定义共享行为的方式。它类似于其他编程语言中的接口或者抽象基类,用于定义一组方法,这些方法可以在多个类型上实现。通过 trait,可以实现多态,并且可以为不同的类型提供统一的接口。 1.1 定义 trait Summary { fn summarize(&self) -> String; } 1.2 默认实现 trait 方法可以提供默认实现。例如: trait Summary { fn summarize(&self) -> String { String::from("(Read more...)") } } 1.3 实现 struct Article { headline: String, content: String, } impl Summary for Article { fn summarize(&self) -> String { format!("{} - {}", self.headline, self.content) } } 1.4 使用 1.4.1 作为函数参数 可以使用 trait 作为函数参数,来接受任何实现了该 trait 的类型。例如: fn notify(item: &impl Summary) { println!

更多 →

June 4, 2024

闭包

闭包(Closures)是一种可以捕获其环境的匿名函数。闭包可以存储在变量中,作为参数传递给其他函数,或者从其他函数中返回。它们可以捕获上下文中的变量,使其在闭包体内使用。 Rust 提供了三种类型的闭包,分别是 Fn、FnMut 和 FnOnce。 闭包语法如下: |参数列表| 表达式 示例: let add = |x, y| x + y; let result = add(2, 3); 带有类型注解的闭包 可以显式地为闭包的参数和返回类型添加类型注解。 let add = |x: i32, y: i32| -> i32 { x + y }; let result = add(2, 3); 💢 闭包捕获环境 闭包可以捕获其定义所在作用域的变量,有三种方式: 按引用捕获(Fn):闭包以不可变引用的方式捕获变量。 按可变引用捕获(FnMut):闭包以可变引用的方式捕获变量。 按值捕获(FnOnce):闭包获取变量的所有权,只能使用一次。 示例: fn main() { let x = 10; // 按引用捕获 let add_to_x = |y: i32| x + y; println!("10 + 5 = {}", add_to_x(5)); let mut z = 10; // 按可变引用捕获 let mut add_to_z = |y: i32| z += y; add_to_z(5); println!

更多 →

June 2, 2024

线程

std::thread::spawn std::thread::spawn 创建一个操作系统级的线程,这些线程在操作系统层面进行调度。它适用于 CPU 密集型任务或者需要与外部库进行 同步操作 的任务。 示例代码 use std::thread; fn main() { let handle = thread::spawn(|| { // 在新的线程中执行 for i in 1..10 { println!("在新线程中:{}", i); std::thread::sleep(std::time::Duration::from_millis(1)); } }); // 在主线程中执行 for i in 1..5 { println!("在主线程中:{}", i); std::thread::sleep(std::time::Duration::from_millis(1)); } handle.join().unwrap(); } spawn 接收一个闭包参数。 tokio::spawn tokio::spawn 创建一个异步任务,这些任务在 Tokio 运行时中进行调度。它适用于 I/O 密集型任务或者需要与其他 异步操作 进行协作的任务。 示例代码 use tokio::time::{sleep, Duration}; #[tokio::main] async fn main() { let handle = tokio::spawn(async { // 在新的异步任务中执行 for i in 1.

更多 →

June 2, 2024