为什么不能将盒装结构作为特征借用?

Why can't a boxed struct be borrowed as a trait?

给定结构 S 实现特征 T,为什么 Box<S> 不实现 Borrow<dyn T>

我希望编译的以下代码没有:

trait T{}
struct S{}
impl T for S{}

fn f1(s: &S) -> &dyn T {
    s
}

fn f2(s: &Box<S>) -> &dyn T {
    std::borrow::Borrow::borrow(s)
}

为什么 f1 可以编译而 f2 不能? (从 &S&dyn T 的转换是在第一种情况下完成的,而不是在第二种情况下完成的)。

&Box<S>不直接等于Box<&S>,这就是为什么不直接编译的原因。

您可以通过 dereferencing 相对轻松地解决此问题,例如:

use std::ops::Deref;
trait T{}
struct S{}
impl T for S{}

fn f1(s : &S) -> &(dyn T) {
    s
}

fn f2(s : &Box<S>) -> &(dyn T) {
    s.deref()
}

(特征 Deref 是为了稍微容易阅读)

deref() 的调用在 &self 上运行,因此 &Box<S> 足以调用它。它只是 returns &S,因为它实现了 T 类型检查。

这与类型推断和类型强制的工作方式有关。 Borrow<B> trait 的参数是借用值的类型,类型检查器需要知道它是什么。

如果你只写:

std::borrow::Borrow::borrow(s)

然后Borrow<B>中的类型B会从周围的代码中推断出来。在您的情况下,它被推断为 dyn T 因为那是 return 值。但是,dyn T 是与 S 完全不同的类型,因此它不进行类型检查。

一旦类型检查器知道 returned 的值是 &S 类型,那么它可以将其强制转换为 &dyn T,但您需要向其提供该信息:

fn f2(s: &Box<S>) -> &dyn T {
    let s: &S = std::borrow::Borrow::borrow(s);
    s
}

或者,更简洁:

fn f2(s: &Box<S>) -> &dyn T {
    std::borrow::Borrow::<S>::borrow(s)
}

起作用的原因是因为 Deref 使用关联类型而不是类型参数。类型检查器可以很容易地推断出 <S as Deref>::Target,因为每个类型只能有一个 Deref 的实现,并且关联的 Target 类型是唯一确定的。 Borrow 是不同的,因为 Box<S> 可以 实现 Borrow<()>Borrow<i32>Borrow<Box<Option<Vec<bool>>>>... 所以你必须更明确地说明您打算使用哪种实现方式。