我正在try 针对现有实现进行一些测试,出于测试目的,我不能更改这些实现.

要想让考试成功,我需要把dyn Thing分变成RealThing分.问题是我收到了一个Arc<Mutex<dyn Thing>>,并且必须在OtherTrait上调用一个为Arc<Mutex<RealThing>>实现的方法.

困惑了吗?是啊,我也是.

这里有一个简单的例子,AnimalMammalHorse更具体地说明:

// The goal here is to cast a dyn Animal into a Horse and
// call a method from Mammal, which is implemented by
// Arc<Mutex<Horse>.   kinda crazy, yeah?

use std::any::Any;
use std::sync::{Arc, Mutex};

// I can't change this
pub trait Animal {

    fn identify(&self) {
        println!("I'm an animal");
    }
    
    fn as_any(&self) -> &dyn Any;
}

// I can't change this
pub trait Mammal {
    fn identify_as_mammal(&self) -> String{
        "I am a mammal".to_string()
    }
}

// I can't change this
struct Horse<G> {
    pub age: G,
}

// I can't change this
impl<G: 'static> Animal for Horse<G> {
    fn as_any(&self) -> &dyn Any {
        self
    }
}

// I especially can't change this.
impl<G> Mammal for Arc<Mutex<Horse<G>>> {}


fn main() {

    // I can't change this.  I receive locked_dyn_animal.
    let horse: Horse<usize> = Horse { age: 10 };
    let locked_dyn_animal: Arc<Mutex<dyn Animal>> = Arc::new(Mutex::new(horse));
    
    // ------  I can only change things below ------

    // Attempt 1: This doesn't compile because it creates Arc<Mutex<&Horse<usize>>> instead of Arc<Mutex<Horse<usize>>>    
    let dyn_animal = locked_dyn_animal.lock().unwrap();
    let horse_ref = <dyn Any>::downcast_ref::<  Horse<usize>  >(&dyn_animal).unwrap();
    let locked_horse = Arc::new(Mutex::new(horse_ref));

    // Attempt 2:  This also doesn't compile for the same reason.
    // let dyn_animal = locked_dyn_animal.lock().unwrap();
    // let horse_ref = dyn_animal.as_any().downcast_ref::< Horse<usize> >().unwrap();
    // let locked_horse = Arc::new(Mutex::new(horse_ref));
    
    let lg = locked_horse.lock().unwrap();
    println!("{}.  My age is {}", lg.identify_as_mammal(), lg.age);
}

Playground

编译错误为:

error[E0599]: no method named `identify_as_mammal` found for struct `MutexGuard<'_, &Horse<usize>>` in the current scope
  --> src/main.rs:60:38
   |
60 |     println!("{}.  My age is {}", lg.identify_as_mammal(), lg.age);
   |                                      ^^^^^^^^^^^^^^^^^^ method not found in `MutexGuard<'_, &Horse<usize>>`
   |
   = help: items from traits can only be used if the trait is implemented and in scope
note: `Mammal` defines an item `identify_as_mammal`, perhaps you need to implement it
  --> src/main.rs:19:1
   |
19 | pub trait Mammal {
   | ^^^^^^^^^^^^^^^^

注意:即使我加上impl<G> Mammal for Arc<Mutex<&Horse<G>>> {},我仍然会得到相同的编译错误.

那么,有什么方法可以做到这一点吗,或者我只是运气不好?

推荐答案

除非您可以在Horse<G>上添加一个Mammal实现,否则如果不克隆Arc<Mutex<_>>中的具体值并创建您自己的包装它的Arc<Mutex<_>>,就无法做到这一点.

注意:即使我加上impl<G> Mammal for Arc<Mutex<&Horse<G>>> {},我仍然会得到相同的编译错误.

如果您在locked_horse上调用特征方法,这应该会起作用,但您的代码不能做到这一点.您的代码做lg.identify_as_mammal(),这是一个引用内部HorseMutexGuard.因此,Arc<Mutex<&Horse<G>>>实现不适用.


您还需要修正这一行,该行试图向下转换MutexGuard而不是包含的值:

let horse_ref = <dyn Any>::downcast_ref::<  Horse<usize>  >(&dyn_animal).unwrap();

在这里,您需要改用as_any特征方法.


解决这两个问题,下面是main()的工作版本:

fn main() {
    // I can't change this.  I receive locked_dyn_animal.
    let horse: Horse<usize> = Horse { age: 10 };
    let locked_dyn_animal: Arc<Mutex<dyn Animal>> = Arc::new(Mutex::new(horse));

    // ------  I can only change things below ------

    // Attempt 1: This doesn't compile because it creates Arc<Mutex<&Horse<usize>>> instead of Arc<Mutex<Horse<usize>>>
    let dyn_animal = locked_dyn_animal.lock().unwrap();
    let horse_ref = <dyn Any>::downcast_ref::<Horse<usize>>(dyn_animal.as_any()).unwrap();
    let locked_horse = Arc::new(Mutex::new(horse_ref));

    // Attempt 2:  This also doesn't compile for the same reason.
    // let dyn_animal = locked_dyn_animal.lock().unwrap();
    // let horse_ref = dyn_animal.as_any().downcast_ref::< Horse<usize> >().unwrap();
    // let locked_horse = Arc::new(Mutex::new(horse_ref));

    let lg = locked_horse.lock().unwrap();
    println!("{}.  My age is {}", locked_horse.identify_as_mammal(), lg.age);
}

在您的实际情况中,如果identify_as_mammal也try 获取锁,则此代码可能会死锁或死机.在这种情况下,您需要在调用identify_as_mammal方法之前或之后释放读取age的锁.

例如,您可以将let lg = locked_horse.lock().unwrap();更改为let age = locked_horse.lock().unwrap().age;,并使用该值而不是lg.age.

Rust相关问答推荐

如何在Rust中获得不可辩驳的'if let'模式警告Mutex锁定?""

将此字符串转换为由空格字符分隔的空格

Rust中的相互递归特性与默认实现

在函数内定义impl和在函数外定义impl的区别

告诉Rust编译器返回值不包含构造函数中提供的引用

可以为rust构建脚本编写单元测试吗?

我如何使用AWS SDK for Rust获取我承担的角色的凭据?

如何使用Actix Web for Rust高效地为大文件服务

Rust编译器似乎被结果类型与anyhow混淆

Rust ndarray:如何从索引中 Select 数组的行

Rust Redis 中的 HSET 命令问题

push 方法是否取得所有权?

分配给下划线模式时会发生什么?

在 Bevy 项目中为 TextureAtlas 精灵实施 NearestNeighbor 的正确方法是什么?

如何从 x86_64 Mac 构建 M1 Mac?

为什么可以在迭代器引用上调用 into_iter?

如何连接 Rust 中的相邻切片

有没有办法隐藏类型定义?

为什么我不能为 Display+Debug 的泛型类型实现 std::error::Error 但有一个不是泛型参数的类型?

为什么我返回的 impl Trait 的生命周期限制在其输入的生命周期内?