为什么不能将盒装结构作为特征借用?
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>>>>
... 所以你必须更明确地说明您打算使用哪种实现方式。
给定结构 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>>>>
... 所以你必须更明确地说明您打算使用哪种实现方式。