簡體   English   中英

如何將混凝土盒裝 object 轉換為盒裝特征 object

[英]How to convert a concrete boxed object to a boxed trait object

肯定有其他方法可以解決這個問題,但我只是好奇是否有任何方法可以使以下代碼在 Rust 中以某種我還不知道的方式工作。

以下代碼示例(操場

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

trait ProvidesFoo {
    fn magic(&mut self);
}

struct Foo {
    magic_value: u32
}

impl Default for Foo {
    fn default() -> Self {
        Self {magic_value: 42}
    }
}

impl ProvidesFoo for Foo {
    fn magic(&mut self) {
        println!("ProvidesFoo magic {}", self.magic_value);
    }
}

pub type SharedFooConcrete = Arc<Mutex<Box<Foo>>>;
pub type SharedFooTraitObj = Arc<Mutex<Box<dyn ProvidesFoo + Send + Sync>>>;

struct FooProvider {
    foo_as_trait_obj: SharedFooTraitObj

}

impl FooProvider {
    fn magic_and_then_some(&mut self) {
        let mut fooguard = self.foo_as_trait_obj.lock().unwrap();
        fooguard.magic();
        println!("Additional magic");
    }
}

fn uses_shared_foo_boxed_trait_obj(foo: SharedFooTraitObj) {
    let mut foo_provider = FooProvider {
        foo_as_trait_obj: foo
    };
    foo_provider.magic_and_then_some();
}
fn uses_shared_foo_concrete(foo: SharedFooConcrete) {
    let mut fooguard = foo.lock().unwrap();
    fooguard.magic();
}

fn main() {
    let shared_foo = Arc::new(Mutex::new(Box::new(Foo::default())));
    uses_shared_foo_concrete(shared_foo.clone());
    uses_shared_foo_boxed_trait_obj(shared_foo);
}

將無法編譯並出現以下錯誤:

error[E0308]: mismatched types
  --> fsrc-example/src/bin/test2.rs:52:37
   |
52 |     uses_shared_foo_boxed_trait_obj(shared_foo);
   |     ------------------------------- ^^^^^^^^^^ expected trait object `dyn ProvidesFoo`, found struct `Foo`
   |     |
   |     arguments to this function are incorrect
   |
   = note: expected struct `Arc<Mutex<Box<(dyn ProvidesFoo + Send + Sync + 'static)>>>`
              found struct `Arc<Mutex<Box<Foo>>>`
note: function defined here

肯定有一種方法可以將盒裝特征 object “轉換”回其具體類型,如此處所示,但這基本上是相反的。 我來自 C++ 背景,所以我對這種類型的 API 很熟悉,其中派生的 object 可以作為基礎 ZA2F822ED4F8EBC26BD4222ED4F8EBC26A14FZ 傳遞

我提到並使用的另一個可能的解決方案是有一個包裝器結構,它具有SharedFooTraitObject作為一個字段並在頂部實現magic_and_then_some()操作。 然后可以傳遞該包裝器結構並克隆Arc<Mutex> ed 字段以獲取僅需要特征 object 的庫代碼。

我只是好奇這種類型的強制/強制轉換在 Rust 中是否可行。

親切的問候,RM

我不確定我是否正確理解您想要什么; 對不起,如果我錯了。

我刪除了所有包裝器類型,以便專注於對具體類型的引用與對 dyn 特征的引用。

提供對具體類型的引用,其中預期對 dyn 特征的引用由語言隱式處理,因為所有信息都是在編譯時提供的。 因為具體類型是眾所周知的,所以可以提供指向適當虛擬表的胖指針。

另一方面,當使用 dyn trait 時,編譯器不再知道原始類型,因此不可能提供對 dyn trait 的引用,而在這種情況下需要對具體類型的引用。

如果我們真的想實現這一點,我們需要一些運行時檢查。 Any trait可以為此提供幫助。 當我們向下轉換時,我們確定了具體類型,然后我們可以獲得對該具體類型的引用。

use std::any::Any;

trait MyTrait: Any {
    fn show(&self);
    fn action(&mut self);
    fn as_any(&self) -> &dyn Any;
    fn as_any_mut(&mut self) -> &mut dyn Any;
}

struct MyStructA {
    value: i32,
}

impl MyStructA {
    fn new(value: i32) -> Self {
        Self { value }
    }
}

impl MyTrait for MyStructA {
    fn show(&self) {
        println!("value is {}", self.value);
    }
    fn action(&mut self) {
        self.value += 1;
        self.show();
    }
    fn as_any(&self) -> &dyn Any {
        self
    }
    fn as_any_mut(&mut self) -> &mut dyn Any {
        self
    }
}

struct MyStructB {
    txt: String,
}

impl MyStructB {
    fn new(txt: String) -> Self {
        Self { txt }
    }
}

impl MyTrait for MyStructB {
    fn show(&self) {
        println!("txt is {}", self.txt);
    }
    fn action(&mut self) {
        self.txt.push_str(" •");
        self.show();
    }
    fn as_any(&self) -> &dyn Any {
        self
    }
    fn as_any_mut(&mut self) -> &mut dyn Any {
        self
    }
}

fn use_impl_trait(t: &mut impl MyTrait) {
    print!("impl: ");
    t.action();
}

fn use_dyn_trait(t: &mut dyn MyTrait) {
    print!("dyn: ");
    t.action();
}

fn main() {
    {
        println!("~~~~ using concrete types ~~~~");
        let mut msa = MyStructA::new(100);
        let msa_ref = &mut msa;
        use_dyn_trait(msa_ref);
        use_impl_trait(msa_ref);
        let mut msb = MyStructB::new("xxx".to_owned());
        let msb_ref = &mut msb;
        use_dyn_trait(msb_ref);
        use_impl_trait(msb_ref);
    }
    {
        println!("~~~~ using dynamic types ~~~~");
        let mut msa = MyStructA::new(200);
        let msa_dyn_ref: &mut dyn MyTrait = &mut msa;
        use_dyn_trait(msa_dyn_ref);
        if let Some(msa_ref) =
            msa_dyn_ref.as_any_mut().downcast_mut::<MyStructA>()
        {
            use_impl_trait(msa_ref);
        }
        let mut msb = MyStructB::new("yyy".to_owned());
        let msb_dyn_ref: &mut dyn MyTrait = &mut msb;
        use_dyn_trait(msb_dyn_ref);
        if let Some(msb_ref) =
            msb_dyn_ref.as_any_mut().downcast_mut::<MyStructB>()
        {
            use_impl_trait(msb_ref);
        }
    }
}
/*
~~~~ using concrete types ~~~~
dyn: value is 101
impl: value is 102
dyn: txt is xxx •
impl: txt is xxx • •
~~~~ using dynamic types ~~~~
dyn: value is 201
impl: value is 202
dyn: txt is yyy •
impl: txt is yyy • •
*/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM