当函数需要 Arc<Mutex<Box<Struct>>> 作为参数时,如何将 Arc<Mutex<Box<dyn Trait>>> 转换为 Arc<Mutex<Box<dyn Trait>>>?

问题描述 投票:0回答:1

当函数需要

Arc<Mutex<Box<Struct>>>
作为参数时,如何将
Arc<Mutex<Box<dyn Trait>>>
转换为
Arc<Mutex<Box<dyn Trait>>>
? 在下面的代码片段中,
age_plus
函数需要
Arc<Mutex<Box<dyn Animal>>>
类型,但只有
Arc<Mutex<Box<Dog>>>
类型可用。

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

pub trait Animal {
    fn age_plus(&mut self) -> u32;
}

pub struct Dog {
    age: u32,
    pub name: String,
}

impl Animal for Dog {
    fn age_plus(&mut self) -> u32 {
        self.age += 1;
        self.age
    }
}
impl Dog {
    pub fn print_name(&self) {
        println!("name: {}", self.name);
    }
}
pub fn age_plus(animal: Arc<Mutex<Box<dyn Animal>>>) {
    animal.lock().unwrap().age_plus();
}
fn main() {
    let dog = Arc::new(Mutex::new(Box::new(Dog {
        age: 10,
        name: "dog".to_string(),
    })));
    dog.lock().unwrap().print_name();
    println!("dog age: {}", dog.lock().unwrap().age_plus());
    // how to convert Arc<Mutex<Box<Dog>>> to Arc<Mutex<Box<dyn Animal>>>?
    age_plus(dog.clone());
}
rust
1个回答
0
投票

这是做不到的。

原因是

Box<Dog>
占用了内存中指针字节的大小,但是
Box<dyn Animal>
占用了内存中指针大小的两倍,因为它还需要存储vtable。所以
Arc<Mutex<Box<Dog>>>
需要成长来容纳
Arc<Mutex<Box<dyn Animal>>>
,这是不可能的。

如果您无法以任何方式更改函数,则唯一的机会就是克隆类型并创建新类型:

let dyn_animal = Arc::new(Mutex::new(Box::new(Dog::clone(&dog.lock().unwrap())) as _));
age_plus(dyn_animal);

当然,

Dog
一定是
Clone
。您也许可以通过从一开始就存储
Box<dyn Animal>
来避免克隆,但如果您需要调用
Dog
特定的方法,则它将不起作用。

另一种可能的选择是,如果您在开始时不需要

Arc<Mutex>
并且之后不需要调用
Dog
特定的方法,则仅构造
Box<dyn Dog>
。这很容易转换为
Box<dyn Animal>
,并且可以稍后用
Arc<Mutex>
包裹:

fn main() {
    let mut dog = Box::new(Dog {
        age: 10,
        name: "dog".to_string(),
    });
    dog.print_name();
    println!("dog age: {}", dog.age_plus());
    let dog = Arc::new(Mutex::new(dog as Box<dyn Animal>));
    age_plus(Arc::clone(&dog));
}

如果您可以更改功能,您有多种选择:

如果可能的话,最好的方法是采用

&mut dyn Animal
,正如 @AleksanderKrauze 所说。这样你就可以提供各种动物:

pub fn age_plus(animal: &mut dyn Animal) {
    animal.age_plus();
}
fn main() {
    let dog = Arc::new(Mutex::new(Box::new(Dog {
        age: 10,
        name: "dog".to_string(),
    })));
    dog.lock().unwrap().print_name();
    println!("dog age: {}", dog.lock().unwrap().age_plus());
    age_plus(&mut **dog.lock().unwrap());
}

如果不可能,请考虑采取

Arc<Mutex<dyn Animal>>
Arc<Mutex<Dog>>
可以转换为:

pub fn age_plus(animal: Arc<Mutex<dyn Animal>>) {
    animal.lock().unwrap().age_plus();
}
fn main() {
    let dog = Arc::new(Mutex::new(Dog {
        age: 10,
        name: "dog".to_string(),
    }));
    dog.lock().unwrap().print_name();
    println!("dog age: {}", dog.lock().unwrap().age_plus());
    age_plus(Arc::clone(&dog) as _);
}
© www.soinside.com 2019 - 2024. All rights reserved.