将 Arc<T> 克隆到 Arc<dyn U>,其中 T 实现 U

Clone Arc<T> into Arc<dyn U> where T implements U

我觉得很奇怪

use std::sync::Arc;

trait Fruit {}
struct Pear {}
impl Fruit for Pear {}

fn main() {
    let pear = Arc::new(Pear {});
    let cloned = Arc::clone(&pear);
    let cloned_casted: Arc<dyn Fruit> = cloned;
}

编译,但是

use std::sync::Arc;

trait Fruit {}
struct Pear {}
impl Fruit for Pear {}

fn main() {
    let pear = Arc::new(Pear {});
    let cloned_casted: Arc<dyn Fruit> = Arc::clone(&pear);
}

错误

error[E0308]: mismatched types
 --> main.rs:9:52
  |
9 |     let cloned_casted: Arc<dyn Fruit> = Arc::clone(&pear);
  |                                                    ^^^^^ expected trait object `dyn Fruit`, found struct `Pear`
  |
  = note: expected reference `&Arc<dyn Fruit>`
             found reference `&Arc<Pear>`

为什么会这样,是否有更短的变体可以从 Arc<Pear> 克隆 Arc<dyn Fruit>

这是 Rust 中类型推断工作方式的结果。方法 Arc::clone() 接受一个 &Arc<T>。编译器需要确定 T 是什么。

在第一个代码片段中,编译器对 Arc::clone(&pear) 的 return 类型没有任何约束,因此它根据传入的参数推断 T . 参数的类型为 &Arc<Pear>,因此编译器推断为 T = Pear。代码片段的最后一行隐式地执行了从 Arc<Pear>Arc<dyn Fruit>.

的未定大小的强制转换。

在第二个代码片段中,编译器已经知道 Arc::clone(&pear) 所需的 return 类型,因为目标变量包含类型注释。基于此,编译器推断 T = dyn Fruit 并期望类型为 &Arc<dyn Fruit> 的参数。但是,它找到了一个 &Arc<Pear>,它不能被强制转换为所需的类型,因此编译器会出错。

目前尚未完全说明 Rust 中类型推断如何工作的细节。每当编译器没有推断出正确的类型时,您应该添加一个显式类型提示:

let pear = Arc::new(Pear {});
let cloned_casted: Arc<dyn Fruit> = Arc::<Pear>::clone(&pear);

这样一来,编译器就不需要推断 T 是什么,并且代码会按预期工作。

有时您还可以让编译器推断出正确的类型。这也有效:

let cloned_casted: Arc<dyn Fruit> = Arc::clone(&pear) as _;

编译器可以将 _ 推断为 Arc<dyn Fruit>,但它不再知道你从 转换什么类型,所以它需要以与第一个代码片段中相同的方式推断该类型。

另请参阅:

除了Sven Marnach的变体,我们还可以做

    let cloned_casted: Arc<dyn Fruit> = pear.clone();