为什么我不能用 let _ 创建 trait 对象:Arc<dyn Trait> = value.into()?

Joh*_*ica 3 generics traits rust trait-objects

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
}
Run Code Online (Sandbox Code Playgroud)

结果

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
}
Run Code Online (Sandbox Code Playgroud)

游乐场

为什么Arc::new(value)编译但不编译value.into()?我不明白为什么Arc<T>::new()满意而From<T>::from不是。

impl<T> Arc<T> {
    pub fn new(data: T) -> Arc<T>
}
Run Code Online (Sandbox Code Playgroud)
impl<T> From<T> for Arc<T> {
    fn from(t: T) -> Arc<T>
}
Run Code Online (Sandbox Code Playgroud)

rod*_*igo 7

你的两条线有根本区别。第一个:

let _: Arc<dyn Trait> = Arc::new(value);
Run Code Online (Sandbox Code Playgroud)

该模式对于 的分辨率并不重要Arc::new(),因为它的定义正如您所指出的:

impl<T> Arc<T> {
    pub fn new(data: T) -> Arc<T>
}
Run Code Online (Sandbox Code Playgroud)

因此,类型T从类型推断valueTraitImplArc<TraitImpl>创建。然后这种类型被隐式地强制转换为该类型,Arc<dyn Trait>并且所有编译都很好。


但第二行更诡异:

let _: Arc<dyn Trait> = value.into();
Run Code Online (Sandbox Code Playgroud)

由于编译器中没有into函数在TraitImpl范围内搜索任何特征并找到Into<T>::into(),因此定义为:

pub trait Into<T> {
    fn into(self) -> T;
}
Run Code Online (Sandbox Code Playgroud)

现在编译器想知道那T是什么类型。既然是函数的返回,它猜测TArc<dyn Trait>。现在唯一有趣的实现IntoFrom

impl<X, T> Into<T> for X where
    T: From<X>
Run Code Online (Sandbox Code Playgroud)

这里XTraitImpl并且TArc<dyn Trait>。如果您查看 for 的 Arc实现From,它包含很多实现,但没有一个适用。这是最相似的:

impl<T> From<T> for Arc<T>
Run Code Online (Sandbox Code Playgroud)

然后,编译器显示一些失败的候选者并发出错误。


TL; DR; 是您实际上想要进行两次转换: from TraitImpltoArc<TraitImpl>和 from Arc<TraitImpl>to Arc<dyn Trait>。但是你不能在一个 coertion 中同时做这两个,编译器必须以某种方式拼出中间类型。