给出一个实现特征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
的转换在第一种情况下完成,而不在第二种情况下完成)。
答案 0 :(得分:3)
这与类型推断和类型强制工作的方式有关。 Borrow<B>
特质的参数是借入值的类型,类型检查器需要知道它是什么。
如果您只写:
std::borrow::Borrow::borrow(s)
然后将从周围的代码中推断出B
中的类型Borrow<B>
。在您的情况下,将其推断为dyn T
,因为这是返回值。但是,dyn T
是与S
完全不同的类型,因此不会进行类型检查。
一旦类型检查器知道返回的值是&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)
}
Sébastien Renauld's answer起作用的原因是,Deref
使用关联的类型而不是类型参数。类型检查器可以轻松推断<S as Deref>::Target
,因为每种类型只能有一个Deref
的实现,并且关联的Target
类型是唯一确定的。 Borrow
有所不同,因为Box<S>
可以实施Borrow<()>
,Borrow<i32>
,Borrow<Box<Option<Vec<bool>>>>
,...因此您必须更加明确关于您打算采用哪种实施方式。
答案 1 :(得分:1)
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
@Html.ActivePage("User", "Index", "User")
@Html.ActivePage("State", "Index", "State")
@Html.ActivePage("City", "Index", "City")
</ul>
</div>
不直接等于&Box<S>
,这就是为什么它不直接编译的原因。
您可以通过dereferencing相对容易地解决此问题,就像这样:
Box<&S>
(具有特征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>
,并且由于实现了&S
类型的检出。