Skip to main content

什么情况下使用 `Deref trait`

鱼雪

Deref trait 是 Rust 中的一个特性,它允许我们重载解引用运算符 *。 这个特性在 Rust 中非常有用, 因为它允许我们在自定义类型上使用解引用运算符,而不需要手动调用 *

在Rust中,Deref trait 是一个非常强大的工具, 它允许你通过解引用运算符*来访问底层数据

Deref trait 最常见的用途之一 是将自定义智能指针类型转换为其内部持有的数据类型。

通过实现 Deref trait,你可以使你的自定义类型与标准库中的类型(如引用和智能指针)具有相同的行为。

使用 Deref 的情形

  • 自定义智能指针:如果你创建了一个自定义智能指针类型,可以通过实现 Deref trait 来使其像标准指针一样工作。
  • 类型转换:当你希望你的类型在某些上下文中像另一个类型一样工作时,可以使用 Deref 进行隐式转换。
  • 函数调用简化:当你希望你的类型能够自动解引用以便调用底层类型的方法时,Deref 非常有用。

情形1: 自定义智能指针

情形说明

  • 如果你创建了一个自定义智能指针类型,可以通过实现 Deref trait 来使其像标准指针一样工作。
use std::ops::Deref;

struct MyBox<T> {
value: T,
}

impl<T> MyBox<T> {
fn new(value: T) -> MyBox<T> {
MyBox { value }
}
}

impl<T> Deref for MyBox<T> {
type Target = T;

fn deref(&self) -> &T {
&self.value
}
}

fn main() {
let x = 5;
let y = MyBox::new(x);

// 通过 Deref trait 自动解引用
println!("Value in MyBox: {}", *y);
}

情形2: 类型转换

情形说明

  • 当你希望你的类型在某些上下文中像另一个类型一样工作时,可以使用 Deref 进行隐式转换
use std::ops::Deref;

struct MyBox<T> {
value: T,
}

impl<T> MyBox<T> {
fn new(value: T) -> MyBox<T> {
MyBox { value }
}
}

impl<T> Deref for MyBox<T> {
type Target = T;

fn deref(&self) -> &T {
&self.value
}
}

fn print_value(value: &i32) {
println!("Value: {}", value);
}

fn main() {
let x = 5;
let y = MyBox::new(x);

// 通过 Deref trait 自动解引用
print_value(&y);
}

情形3: 函数调用简化

情形说明

  • 当你希望你的类型能够自动解引用以便调用底层类型的方法时,Deref 非常有用
use crate::{AppError, User};
use jwt_simple::prelude::*;
use std::ops::Deref;

const JWT_DURATION: u64 = 60 * 60 * 24 * 7;

pub struct EncodingKey(Ed25519KeyPair);
pub struct DecodingKey(Ed25519PublicKey);

impl EncodingKey {
pub fn load(pem: &str) -> Result<Self, AppError> {
Ok(Self(Ed25519KeyPair::from_pem(pem)?))
}

pub fn sign(user: User, key: &EncodingKey) -> Result<String, AppError> {
let claims = Claims::with_custom_claims(user, Duration::from_secs(JWT_DURATION));
Ok(key.sign(claims)?) // 这里key为引用,但是我们想要像操作结构体本身一样使用
}
}

impl DecodingKey {
pub fn load(pem: &str) -> Result<Self, AppError> {
Ok(Self(Ed25519PublicKey::from_pem(pem)?))
}

pub fn verify(token: &str, key: &DecodingKey) -> Result<User, AppError> {
let claims = key.verify_token::<User>(token, None)?; // 这里key为引用,但是我们想要像操作结构体本身一样使用
Ok(claims.custom)
}
}

impl Deref for EncodingKey {
type Target = Ed25519KeyPair;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl Deref for DecodingKey {
type Target = Ed25519PublicKey;

fn deref(&self) -> &Self::Target {
&self.0
}
}

如果参数传递的是结构体的引用,并且你想要在使用该引用时像操作结构体本身一样使用

那么实现 Deref trait 是一个很好的选择

通过实现 Deref trait,你可以让结构体的引用表现得像结构体本身一样,从而简化代码并提高可读性。

总结

Deref trait 主要用在智能指针类型和自定义类型上, 它可以帮助我们简化代码、减少重复、提高可读性。

Rust中传参,优先使用引用,而不是值, 实现 Deref trait 可以让你在使用引用时像操作结构体本身一样使用, 从而提高代码的可读性和简洁性。