gpt4 book ai didi

generics - 何时以及为何使用 AsRef 而不是 &T

转载 作者:行者123 更新时间:2023-12-03 11:27:18 24 4
gpt4 key购买 nike

AsRef 文档写道

Used to do a cheap reference-to-reference conversion.


我理解 reference-to-reference 部分 cheap 是什么意思?我希望它与复杂性理论(大哦,等等)“便宜”无关。
例子:
User {
email: String,
age: u8,
}

impl AsRef<User> for User {
fn as_ref(&self) -> &User {
&self
}
}

fn main() {
let user = User { email: String::from("myemail@example.com"), age: 25 };
let user_ref = &user;
//...
}
如果我可以通过简单的 AsRef 获取引用,那么为 User 实现 &user 的原因是什么?
实现 AsRef 的规则是什么?
PS:我在其他论坛和文档中找不到任何可以回答这些问题的内容。

最佳答案

正如您所指出的, impl AsRef<User> for User 似乎有点毫无意义,因为您可以只执行 &user 。您可以使用 impl AsRef<String> for Userimpl AsRef<u8> for User 作为 &user.email&user.age 的替代品,但这些示例可能是对特性的误用。能够将 User 转换为 &String 是什么意思? &String 是他们的电子邮件、名字、姓氏、密码吗?它没有多大意义,并且在 User 具有多个 String 字段时分崩离析。
假设我们开始编写一个应用程序,并且我们只有 User 带有电子邮件和年龄。我们会像这样在 Rust 中建模:

struct User {
email: String,
age: u8,
}
假设一段时间过去了,我们编写了一堆函数,我们的应用程序变得非常流行,我们决定允许用户成为版主,版主可以拥有不同的版主权限。我们可以这样建模:
struct User {
email: String,
age: u8,
}

enum Privilege {
// imagine different moderator privileges here
}

struct Moderator {
user: User,
privileges: Vec<Privilege>,
}
现在我们可以直接将 privileges 向量添加到 User 结构体中,但由于不到 1% 的 User 将是 Moderator ,因此将向量添加到每个 User 似乎是浪费内存。添加 Moderator 类型导致我们编写稍微笨拙的代码,因为我们所有的函数仍然采用 User s,所以我们必须将 &moderator.user 传递给它们:
#[derive(Default)]
struct User {
email: String,
age: u8,
}

enum Privilege {
// imagine different moderator privileges here
}

#[derive(Default)]
struct Moderator {
user: User,
privileges: Vec<Privilege>,
}

fn takes_user(user: &User) {}

fn main() {
let user = User::default();
let moderator = Moderator::default();

takes_user(&user);
takes_user(&moderator.user); // awkward
}
如果我们可以将 &moderator 传递给任何需要 &User 的函数,那就太好了,因为版主实际上只是具有一些附加权限的用户。使用 AsRef 我们可以!这是我们如何实现的:
#[derive(Default)]
struct User {
email: String,
age: u8,
}

// obviously
impl AsRef<User> for User {
fn as_ref(&self) -> &User {
self
}
}

enum Privilege {
// imagine different moderator privileges here
}

#[derive(Default)]
struct Moderator {
user: User,
privileges: Vec<Privilege>,
}

// since moderators are just regular users
impl AsRef<User> for Moderator {
fn as_ref(&self) -> &User {
&self.user
}
}

fn takes_user<U: AsRef<User>>(user: U) {}

fn main() {
let user = User::default();
let moderator = Moderator::default();

takes_user(&user);
takes_user(&moderator); // yay
}
现在我们可以将 &Moderator 传递给任何需要 &User 的函数,它只需要一个小的代码重构。此外,这种模式现在可以扩展到任意多种用户类型,我们可以添加 Admin s 和 PowerUser s 和 SubscribedUser s,只要我们为它们实现 AsRef<User> ,它们就可以与我们的所有函数一起使用。 &Moderator&User 开箱即用的原因是因为标准库中的 this generic blanket implementation :
impl<T: ?Sized, U: ?Sized> AsRef<U> for &T
where
T: AsRef<U>,
{
fn as_ref(&self) -> &U {
<T as AsRef<U>>::as_ref(*self)
}
}
这基本上只是说如果我们有一些 impl AsRef<User> for &Moderator,我们也会自动免费获得所有 impl AsRef<U> for Timpl AsRef<U> for &T

关于generics - 何时以及为何使用 AsRef<T> 而不是 &T,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66026309/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com