Appearance
常见Trait使用
FromStr
假设你有一个字符串"42",你想要将它解析为i32类型的数字:
rust
let num_str = "42";
let num: i32 = num_str.parse().unwrap();
println!("Parsed number: {}", num);
let num_str = "42";
let num: i32 = num_str.parse().unwrap();
println!("Parsed number: {}", num);
对于自定义类型,如果你想能够使用parse
方法将字符串转换为该类型的实例,你需要手动实现FromStr trait
。下面是一个简单的例子,展示了如何为自定义类型实现FromStr
:
rust
use std::str::FromStr;
struct Point {
x: i32,
y: i32,
}
impl FromStr for Point {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts: Vec<&str> = s.split(',').collect();
if parts.len() != 2 {
return Err("Input must be in the format 'x,y'".to_string());
}
let x = parts[0].parse::<i32>().map_err(|_| "Invalid integer")?;
let y = parts[1].parse::<i32>().map_err(|_| "Invalid integer")?;
Ok(Point { x, y })
}
}
fn main() {
let point_str = "3,4";
let point: Point = point_str.parse().unwrap();
println!("Parsed point: ({}, {})", point.x, point.y);
}
use std::str::FromStr;
struct Point {
x: i32,
y: i32,
}
impl FromStr for Point {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts: Vec<&str> = s.split(',').collect();
if parts.len() != 2 {
return Err("Input must be in the format 'x,y'".to_string());
}
let x = parts[0].parse::<i32>().map_err(|_| "Invalid integer")?;
let y = parts[1].parse::<i32>().map_err(|_| "Invalid integer")?;
Ok(Point { x, y })
}
}
fn main() {
let point_str = "3,4";
let point: Point = point_str.parse().unwrap();
println!("Parsed point: ({}, {})", point.x, point.y);
}
Add
为Point结构体实现Add<Size>特征,以便可以将Point和Size相加:
rust
#[derive(Debug, PartialEq)]
struct Point {
x: i32,
y: i32,
}
#[derive(Debug, PartialEq)]
struct Size {
width: i32,
height: i32,
}
use std::ops::Add;
impl Add<Size> for Point {
type Output = Point;
fn add(self, other: Size) -> Point {
Point {
x: self.x + other.width,
y: self.y + other.height,
}
}
}
#[derive(Debug, PartialEq)]
struct Point {
x: i32,
y: i32,
}
#[derive(Debug, PartialEq)]
struct Size {
width: i32,
height: i32,
}
use std::ops::Add;
impl Add<Size> for Point {
type Output = Point;
fn add(self, other: Size) -> Point {
Point {
x: self.x + other.width,
y: self.y + other.height,
}
}
}
需要注意的是,谁在前面,谁就要实现Add特征。
如果是 Point + Point 就不需要给Add传泛型参数
Send
- 一个任务要实现 Send 特征,那它在 .await 调用的过程中所持有的全部数据都必须实现 Send 特征
- 若实现了 Send 特征(可以在线程间安全地移动),那任务自然也就可以在线程间安全地移动。
Deref 和 DerefMut
在 Rust 中,Deref 和 DerefMut trait 允许重载解引用运算符(*)。通过实现这些 trait,可以自定义当类型被解引用时的行为。这是 Rust 提供的一种智能指针模式,使得自定义类型的行为更接近内建引用。
- Deref
rust
use std::ops::Deref;
struct MyBox<T>(T);
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
fn main() {
let x = MyBox(5);
assert_eq!(5, *x); // 使用了Deref trait
}
use std::ops::Deref;
struct MyBox<T>(T);
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
fn main() {
let x = MyBox(5);
assert_eq!(5, *x); // 使用了Deref trait
}
- DerefMut
rust
use std::ops::{Deref, DerefMut};
impl<T> DerefMut for MyBox<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
fn main() {
let mut x = MyBox(5);
*x = 6; // 使用了DerefMut trait
assert_eq!(6, *x);
}
use std::ops::{Deref, DerefMut};
impl<T> DerefMut for MyBox<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
fn main() {
let mut x = MyBox(5);
*x = 6; // 使用了DerefMut trait
assert_eq!(6, *x);
}
Rust 会自动使用 Deref
和 DerefMut
来进行类型之间的强制转换,使得函数或方法调用更加灵活。这意味着当你调用一个需要特定引用类型的函数或方法时,如果提供了一个实现了 Deref
(或 DerefMut
)的类型,Rust 会自动解引用为目标类型。
rust
fn print_str(s: &str) {
println!("{}", s);
}
fn main() {
let my_string = MyBox(String::from("Hello, Rust!"));
print_str(&*my_string); // 显式解引用
print_str(&my_string); // 自动解引用强制转换
}
fn print_str(s: &str) {
println!("{}", s);
}
fn main() {
let my_string = MyBox(String::from("Hello, Rust!"));
print_str(&*my_string); // 显式解引用
print_str(&my_string); // 自动解引用强制转换
}
如上,MyBox自动解引用会经过以下步骤:
- 发现你想把一个my_string(MyBox类型)引用转为&str
- 解引用 *my_string
- &*my_string 获取引用
ToOwned
它可以把借用的数据克隆出一个拥有所有权的数据。
rust
let s: &str = "a";
let ss: String = s.to_owned();
let v: &[i32] = &[1, 2];
let vv: Vec<i32> = v.to_owned();
let s: &str = "a";
let ss: String = s.to_owned();
let v: &[i32] = &[1, 2];
let vv: Vec<i32> = v.to_owned();