繁体   English   中英

为什么我不能用 let _: Arc 创建一个特征 object<dyn trait> = value.into()?</dyn>

[英]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是从TraitImplvalue类型推导出来的,并创建了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 的返回,它猜测TArc<dyn Trait> 现在Into唯一有趣的实现是在From方面:

impl<X, T> Into<T> for X where
    T: From<X>

这里XTraitImplTArc<dyn Trait> 如果您查看Arc for From的 impl,它包含了很多,但没有一个适用。 这是最相似的:

impl<T> From<T> for Arc<T>

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


TL;DR; 是您实际上想要进行两次转换:从TraitImplArc<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要求RustArc<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
}

在此示例中,您清楚地表明您将从一个大小的类型转换为另一个大小的类型,即TraitImplArc<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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM