[英]Why can't a boxed struct be borrowed as a trait?
给定实现特征T
的结构S
,为什么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
的转换在第一种情况下完成,而不是在第二种情况下完成)。
这与类型推断和类型强制工作的方式有关。 Borrow<B>
特征的参数是借入值的类型,类型检查器需要知道它的含义。
如果您只写:
std::borrow::Borrow::borrow(s)
然后从周围的代码中推断出Borrow<B>
的类型B
在您的情况下,可以推断为dyn T
因为这是返回值。 但是, dyn T
是与S
完全不同的类型,因此不进行类型检查。
一旦类型检查器知道返回的值是&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ébastienRenauld的答案之所以起作用,是因为Deref
使用关联的类型而不是类型参数。 类型检查器可以轻松推断<S as Deref>::Target
因为每种类型只能有一个Deref
实现,并且关联的Target
类型是唯一确定的。 Borrow
有所不同,因为Box<S>
可以实现Borrow<()>
, Borrow<i32>
, Borrow<Box<Option<Vec<bool>>>>
,...,因此您必须更明确地了解打算实现的实现。
&Box<S>
不直接等于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
,并且由于实现T
所以类型检出。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.