[英]Why can't `&(?Sized + Trait)` be cast to `&dyn Trait`?
[英]Why can't I create a trait object with let _: Arc<dyn Trait> = value.into()?
use std::sync::Arc;
trait Trait {}
struct TraitImpl {}
impl Trait for TraitImpl {}
fn main() {
let value = TraitImpl {};
let _: Arc<dyn Trait> = Arc::new(value); // compiles
let _: Arc<dyn Trait> = value.into(); // doesn't compile
}
结果
error[E0277]: the trait bound `std::sync::Arc<dyn Trait>: std::convert::From<TraitImpl>` is not satisfied
--> src/main.rs:10:35
|
10 | let _: Arc<dyn Trait> = value.into(); // doesn't compile
| ^^^^ the trait `std::convert::From<TraitImpl>` is not implemented for `std::sync::Arc<dyn Trait>`
|
= help: the following implementations were found:
<std::sync::Arc<T> as std::convert::From<T>>
<std::sync::Arc<T> as std::convert::From<std::boxed::Box<T>>>
<std::sync::Arc<[T]> as std::convert::From<&[T]>>
<std::sync::Arc<[T]> as std::convert::From<std::vec::Vec<T>>>
and 8 others
= note: required because of the requirements on the impl of `std::convert::Into<std::sync::Arc<dyn Trait>>` for `TraitImpl`
( 游乐场)
为什么Arc::new(value)
编译而不是value.into()
? 我不明白为什么Arc<T>::new()
满足而From<T>::from
不满足。
impl<T> Arc<T> {
pub fn new(data: T) -> Arc<T>
}
impl<T> From<T> for Arc<T> {
fn from(t: T) -> Arc<T>
}
你的两条线有根本的区别。 第一个:
let _: Arc<dyn Trait> = Arc::new(value);
该模式对于Arc::new()
的分辨率并不重要,因为它的定义如您所述:
impl<T> Arc<T> {
pub fn new(data: T) -> Arc<T>
}
因此类型T
是从TraitImpl
的value
类型推导出来的,并创建了Arc<TraitImpl>
。 然后这个类型被隐式地强制转换为Arc<dyn Trait>
并且所有编译都很好。
但第二行更狡猾:
let _: Arc<dyn Trait> = value.into();
由于在 TraitImpl 中没有into
function ,因此编译器在TraitImpl
中搜索任何特征并找到Into<T>::into()
,其定义为:
pub trait Into<T> {
fn into(self) -> T;
}
现在编译器想知道那个T
是什么类型。 由于是 function 的返回,它猜测T
是Arc<dyn Trait>
。 现在Into
唯一有趣的实现是在From
方面:
impl<X, T> Into<T> for X where
T: From<X>
这里X
是TraitImpl
, T
是Arc<dyn Trait>
。 如果您查看Arc
for From
的 impl,它包含了很多,但没有一个适用。 这是最相似的:
impl<T> From<T> for Arc<T>
然后,编译器显示一些失败的候选并发出错误。
TL;DR; 是您实际上想要进行两次转换:从TraitImpl
到Arc<TraitImpl>
,然后从Arc<TraitImpl>
到Arc<dyn Trait>
。 但是你不能在一个单一的强制中做到这两个,编译器必须以某种方式拼写出中间类型。
对于所有通用 Rust 代码,任何T
上都有一个隐式Sized
界限。 这个:
fn func<T>(t: &T) {}
其实是这样的:
fn func<T: Sized>(t: &T) {}
这可能并不总是您想要的,因此这是您必须明确选择退出的唯一特征,如下所示:
fn func<T: ?Sized>(t: &T) {}
所以在你的情况下:
impl<T> From<T> for Arc<T> {
fn from(t: T) -> Arc<T>
}
实际上是:
impl<T: Sized> From<T> for Arc<T> {
fn from(t: T) -> Arc<T>
}
这就是为什么你不能some_value.into()
一个Arc<dyn Anything>
因为所有特征对象都没有大小。
至于为什么首先存在这种限制,我们可以通过查看From<T>
的定义来确定:
pub trait From<T> {
fn from(T) -> Self;
}
from(T)
意味着它必须获取一些T
并将其放入函数的调用堆栈中,这意味着T
在编译时必须具有已知大小,因此必须为Sized
。
更新
所以这也适用于Arc::new(T)
因为 function 在 impl 块中定义,如下所示:
impl<T> for Arc<T> {
fn new(T) -> Arc<T> {
...
}
}
当你调用Arc::new(TraitImpl);
您确实使用Sized
类型调用它,因为TraitImpl
的大小在编译时是已知的,但是由于let
要求Rust将Arc<TraitImpl>
视为Arc<dyn Trait>
。
当您调用value.into()
时,不会触发这种 unsized 强制,因为From<T>
只接受Sized
类型。
但是,如果您决定使用From<T>
,您可以这样做:
use std::sync::Arc;
trait Trait {}
struct TraitImpl {}
impl Trait for TraitImpl {}
fn main() {
let value = TraitImpl {};
let _: Arc<dyn Trait> = Arc::new(value); // compiles
let value = TraitImpl {};
let _: Arc<dyn Trait> = <Arc<TraitImpl>>::from(value); // also compiles
}
在此示例中,您清楚地表明您将从一个大小的类型转换为另一个大小的类型,即TraitImpl
到Arc<TraitImpl>
,然后触发未调整大小的强制Arc<TraitImpl>
到Arc<dyn Trait>
。
以下是其他变体:
use std::sync::Arc;
trait Trait {}
struct TraitImpl {}
impl Trait for TraitImpl {}
fn main() {
let value = TraitImpl {};
let _: Arc<dyn Trait> = Arc::new(value); // compiles
let value = TraitImpl {};
let _: Arc<dyn Trait> = <Arc<TraitImpl>>::from(value); // compiles
let value = TraitImpl {};
let _: Arc<dyn Trait> = Arc::from(value); // compiles, can infer Arc<TraitImpl> here
let value = TraitImpl {};
let _: Arc<dyn Trait> = Into::<Arc<TraitImpl>>::into(value); // compiles
let value = TraitImpl {};
let _: Arc<dyn Trait> = Into::<Arc<_>>::into(value); // compiles, can infer Arc<TraitImpl> here
let value = TraitImpl {};
let _: Arc<dyn Trait> = Into::into(value); // doesn't compile, infers Arc<dyn Trait> here
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.