Har*_*ork 7 generics polymorphism traits rust parametric-polymorphism
AsRef 文档写入
用于进行廉价的引用到引用转换。
我明白reference-to-reference部分是什么意思cheap?我希望它与复杂性理论(大哦,等等)“便宜”无关。
例子:
struct 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;
//...
}
Run Code Online (Sandbox Code Playgroud)
什么是执行的原因AsRef为User,如果我可以随便拿一个参考&user?执行的规则是AsRef什么?
PS:我在其他论坛和文档中找不到任何可以回答这些问题的内容。
Mas*_*inn 19
我希望它与复杂性理论(大哦,等等)“便宜”无关。
确实如此。AsRef基本上不需要任何成本。
如果我可以简单地通过 &user 进行引用,那么为什么要为 User 实现 AsRef 呢?
应该没有吧 AsRef对于通用代码很有用,特别是(但不限于)人体工程学。
例如,如果std::fs::rename采取了&Path你必须写:
fs::rename(Path::new("a.txt"), Path::new("b.txt"))?;
Run Code Online (Sandbox Code Playgroud)
这是冗长且烦人的。
然而,由于它确实需要AsRef<Path>使用字符串,所以它可以开箱即用,这意味着您只需调用:
fs::rename("a.txt", "b.txt")?;
Run Code Online (Sandbox Code Playgroud)
这是非常简单并且更具可读性的。
kfe*_*v91 15
正如您所指出的,impl AsRef<User> for User似乎有点毫无意义,因为您可以只做&user. 你可以做impl AsRef<String> for User或impl AsRef<u8> for User作为替代品&user.email,&user.age但这些例子可能是对特征的滥用。能够将 a 转换为 an是什么意思?是他们的电子邮件、他们的名字、他们的姓氏、他们的密码吗?它没有多大意义,并且在 a拥有多个领域时分崩离析。User&String&StringUserString
假设我们开始编写一个应用程序,我们只有User电子邮件和年龄。我们会像这样在 Rust 中建模:
struct User {
email: String,
age: u8,
}
Run Code Online (Sandbox Code Playgroud)
假设一段时间过去了,我们编写了一堆函数,我们的应用程序变得非常流行,我们决定允许用户成为版主,版主可以拥有不同的版主权限。我们可以这样建模:
struct User {
email: String,
age: u8,
}
enum Privilege {
// imagine different moderator privileges here
}
struct Moderator {
user: User,
privileges: Vec<Privilege>,
}
Run Code Online (Sandbox Code Playgroud)
现在我们可以privileges直接将向量添加到User结构体中,但由于少于 1% 的Users 将是Moderators,因此向每个User. 添加的Moderator类型会导致我们写略显尴尬的代码,但因为我们所有的功能仍然采取User如此的,我们必须通过&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
}
Run Code Online (Sandbox Code Playgroud)
如果我们可以传递&moderator给任何需要 an 的函数,那就太好了,&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
}
Run Code Online (Sandbox Code Playgroud)
现在我们可以将 a 传递&Moderator给任何&User需要 a 的函数,它只需要一个小的代码重构。此外,这种模式现在可以扩展到任意多种用户类型,我们可以添加Admins 和PowerUsers 和SubscribedUsers,只要我们AsRef<User>为它们实现,它们将适用于我们的所有功能。
之所以&Moderator要&User开箱的没有我们需要写一个明确的impl AsRef<User> for &Moderator是,因为这个通用毯执行标准库:
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)
}
}
Run Code Online (Sandbox Code Playgroud)
这基本上是说,如果我们有一些impl AsRef<U> for T我们还可以自动获得impl AsRef<U> for &T所有T免费的。