Can I throw between two traits?

I swear I searched the entire Internet, and I tried very hard to understand all the answers that I found that were related. However, I still do not understand if this is possible or not.

trait Foo {
    fn do_foo (&self);
}

trait Bar {
    fn do_bar (&self);
}

struct SomeFoo;

impl Foo for SomeFoo {
    fn do_foo(&self) {
        println!("doing foo");
    }
}

struct SomeFooBar;

impl Foo for SomeFooBar {
    fn do_foo(&self) {
        println!("doing foo");
    }
}

impl Bar for SomeFooBar {
    fn do_bar(&self) {
        println!("doing bar");
    }
}


fn main () {
    let foos:Vec<Box<Foo>> = vec!(Box::new(SomeFoo), Box::new(SomeFooBar));

    for foo in foos {
        foo.do_foo();

        /*        
        if let Some(val) = foo.downcast_whatever<Bar>() {
            val.bar();
        }*/
    }
}

Playpen: http://is.gd/CPnSCu

My question is mainly if there is a way to drop from one sign to another.

I have two traits Fooand Barand a Vec<Box<Foo>>. I know that some elements in vec implement the trait Bar, and I wonder if there is a way I could target them?

Update

The only solution that I have found so far is to introduce the 3rd sign FooOrBarwith explicit conversion methods and implement this for both types. This doesn't seem like the right tool to work though;)

trait FooOrBar {
    fn to_bar(&self) -> Option<&Bar>;
    fn to_foo(&self) -> Option<&Foo>;
}

impl FooOrBar for SomeFooBar {
    fn to_bar(&self) -> Option<&Bar> {
        Some(self)
    }

    fn to_foo(&self) -> Option<&Foo> {
        None
    }
}

impl FooOrBar for SomeFoo {
    fn to_bar(&self) -> Option<&Bar> {
        None
    }

    fn to_foo(&self) -> Option<&Foo> {
        Some(self)
    }
}

fn main () {

    let foos:Vec<Box<FooOrBar>> = vec!(Box::new(SomeFoo), Box::new(SomeFooBar));

    for foo in foos {
        foo.to_foo().map(|foo| foo.do_foo());
        foo.to_bar().map(|foo| foo.do_bar());
    }
}
+3
4

. . , , , . TraitObject.

TraitObject - , . : data vtable. data - :

#![feature(raw)]

trait Foo {}
impl Foo for u8 {}

use std::{raw, mem};

fn main() {
    let i = 42u8;
    let t = &i as &Foo;
    let to: raw::TraitObject = unsafe { mem::transmute(t) };

    println!("{:p}", to.data);
    println!("{:p}", &i);
}

vtable . , .

// For this hypothetical input
trait Foo {
    fn one(&self);
}

impl Foo for u8 {
    fn one(&self) { println!("u8!") }
}

// The table is something like this pseudocode
const FOO_U8_VTABLE = [impl_of_foo_u8_one];

, - , . no way, .

, . , vtable, . , ( ).

data TraitObject struct

, . - . , , - , . &Foo &u8 &(), , , .

Any trait , . , .

- , , FooOrBar, , , ?

  • , as_foo Bar .

  • , Box<Foo>, Box<Bar>, .

  • Bar foo .

  • Quux, <FooStruct as Quux>::quux Foo::foo <BarStruct as Quux>::quux Bar::foo, Bar::bar.

+7

... , , , , .

// first indirection: trait objects
let sf: Box<Foo> = Box::new(SomeFoo);
let sb: Box<Bar> = Box::new(SomeFooBar);

// second level of indirection: Box<Any> (Any in this case
// is the first Box with the trait object, so we have a Box<Box<Foo>>
let foos: Vec<Box<Any>> = vec![Box::new(sf), Box::new(sb)];

// downcasting to the trait objects
for foo in foos {
    match foo.downcast::<Box<Foo>>() {
        Ok(f) => f.do_foo(),
        Err(other) => {
            if let Ok(bar) = other.downcast::<Box<Bar>>() {
                    bar.do_bar();
            }
        }
    }
}

, SomeFooBar Box<Bar> , Box<Bar> . , , (SomeFooBar Foo, Box<Foo>, )

+2

: downcasting.


, :

  • , , .
  • , downcasting ( )

, , , , Rust - , .

:

  • TypeId: TypeId, , , Any , , , X. Any TypeId X TypeId .

  • trait, .

, , , .

+2

.

as_bar Foo, Option<&Bar>. None, Foo , Bar.

trait Foo {
    fn do_foo (&self);
    fn as_bar(&self) -> Option<&Bar> {
        None
    }
}

SomeFooBar, Foo, Bar, , Some(self).

impl Foo for SomeFooBar {
    fn do_foo(&self) {
        println!("doing foo");
    }

    fn as_bar(&self) -> Option<&Bar>{
        Some(self)
    }
}

, , .

let foos:Vec<Box<Foo>> = vec!(Box::new(SomeFoo), Box::new(SomeFooBar));

for foo in foos {
    foo.do_foo();

    if let Some(bar) = foo.as_bar() {
        bar.do_bar();
    }
}

: http://is.gd/JQdyip

I would like to see how rust improves in this part in the future, but this is a decision that I can live with in my case.

+2
source

Source: https://habr.com/ru/post/1678552/


All Articles