当函数需要
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());
}
这是做不到的。
原因是
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 _);
}