为什么 Deref::deref 的返回类型本身是一个引用?

问题描述 投票:0回答:3

我正在阅读 Rust 的

Deref
特性的文档:

pub trait Deref {
    type Target: ?Sized;
    fn deref(&self) -> &Self::Target;
}

deref
函数的类型签名对我来说似乎违反直觉;为什么返回类型是引用?如果引用实现了此特征,以便可以取消引用它们,这会产生什么影响?

我能想到的唯一解释是引用没有实现

Deref
,但被认为是“原始可解引用”。但是,如何编写适用于 any 可解引用类型(包括
Deref<T>
&T
)的多态函数呢?

pointers reference rust
3个回答
19
投票

参考文献未实现

Deref

您可以看到 所有实现

Deref
的类型,并且
&T
都在该列表中:

impl<'a, T> Deref for &'a T where T: ?Sized

不明显的事情是,当您将

*
运算符与实现
Deref
的东西一起使用时,会应用语法糖。看看这个小例子:

use std::ops::Deref;

fn main() {
    let s: String = "hello".into();
    let _: () = Deref::deref(&s);
    let _: () = *s;
}
error[E0308]: mismatched types
 --> src/main.rs:5:17
  |
5 |     let _: () = Deref::deref(&s);
  |                 ^^^^^^^^^^^^^^^^ expected (), found &str
  |
  = note: expected type `()`
             found type `&str`

error[E0308]: mismatched types
 --> src/main.rs:6:17
  |
6 |     let _: () = *s;
  |                 ^^ expected (), found str
  |
  = note: expected type `()`
             found type `str`

deref
的显式调用返回
&str
,但运算符
*
返回
str
。这更像是您在调用
*Deref::deref(&s)
,忽略隐含的无限递归 (请参阅文档)

Xirdus 的说法是正确的

如果

deref
返回一个值,它要么是无用的,因为它总是会移出,要么具有与其他函数截然不同的语义

虽然“没用”有点强;它对于实现

Copy
的类型仍然有用。

另请参阅:

请注意,上述所有内容对于

Index
IndexMut
也同样有效。


10
投票

编译器只知道如何取消引用 & 指针 - 但它也知道实现

Deref
特征的类型有一个
deref()
方法,可用于获取对给定对象内某些内容的适当引用。如果您取消引用一个对象,您实际上要做的是首先获取引用,然后才取消引用它。

如果

deref()
返回一个值,它要么是无用的,因为它总是会移出,要么具有与其他函数截然不同的语义,这不太好。


0
投票

解除引用是两部分操作。一种是引用数据,另一种是访问引用背后的数据——这是在解引用运算符

*
的帮助下完成的。
Deref
特性仅完成第一部分——获取参考,然后将其提供给我们。然后解引用运算符
*
跟随引用(内存地址)并让我们访问该内存地址上的数据——这部分确实是编译器内置的。

fn main()
{
    let age: i32 = 90;
    let r_age = &age;       // first part: taking reference
    println!("{}", *r_age); // second part: accessing the reference
}

现在,如果我们没有引用,我们如何使用解引用运算符来访问数据

*

fn main()
{
   let age: i32 = 90;
   //println!("{}", *age);   // will not work, we did not take reference of age.
   println!("{}", *(&age));
}

现在可以为我们自己的类型实现

Deref
特征。

use std::ops::Deref; 

fn main()
{
   let d = OurOwnType(77);
   println!("{}", *d);
   println!("{}", *(d.deref()));
   println!("{}", *(Deref::deref(&d)));
   println!("{}", *(&d.0));
}

struct OurOwnType(i32);

impl std::ops::Deref for OurOwnType
{
    type Target = i32;
    fn deref(&self) -> &Self::Target
    {
        &self.0
    }
}

*d
编译器的幕后调用
deref
特征中的
Deref
方法,如提供引用的
d.deref()
,然后在解引用运算符
*
的帮助下进行解引用操作,让我们可以访问数据。这里的
Deref
特性完成了为我们提供参考的第一部分。

© www.soinside.com 2019 - 2024. All rights reserved.