Do I need multiple impl blocks to implement multip

2019-07-25 15:40发布

Consider this code that defines a trait RefGen, a structure Facade that has a property that can hold a RefGen and two different new_* methods that would pick different concrete implementations for the RefGen.

trait RefGen {
    fn gen() -> String;
}

struct FooGen;

impl RefGen for FooGen {
    fn gen() -> String {
        "foo".to_owned()
    }
}

struct BarGen;

impl RefGen for BarGen {
    fn gen() -> String {
        "bar".to_owned()
    }
}

struct Facade<R: RefGen> {
    gen: R
}

impl Facade<FooGen> {
    fn new_foogen() -> Self {
        Facade {
            gen: FooGen
        }
    }
}

impl Facade<BarGen> {
    fn new_bargen() -> Self {
        Facade {
            gen: BarGen
        }
    }
}

fn main () {}

It works, but it baffles me I would need two impl blocks for that?

标签: generics rust
1条回答
走好不送
2楼-- · 2019-07-25 16:31

If you want named methods for each type, this is the only way. If you want to do this generically, you can use a generic impl:

impl<R: RefGen> Facade<R> {
    fn new() -> Self {
        Facade {
            gen: R::new(),
        }
    }
}

This of course requires the RefGen trait to offer some kind of new function to create instances:

trait RefGen {
    fn gen() -> String;
    fn new() -> Self where Self: Sized;
}

The where Self: Sized bound is there so the trait is still object safe. This means that you can create a Box<RefGen>, but not call the new method.

Though now you cannot call the gen method on your GenFoo or GenBar object, because it's a static method. You need to add a &self parameter to it. In case you never want to actually create an object of type GenFoo or GenBar, because they will never have fields, you can get rid of the gen field and new constructor entirely by doing all dispatch at compile-time:

struct Facade<R: RefGen> {
    gen: PhantomData<R>,
}

impl<R: RefGen> Facade<R> {
    fn new() -> Self {
        Facade {
            gen: PhantomData,
        }
    }
    fn gen(&self) -> String {
        R::gen()
    }
}

impl Facade<FooGen> {
    fn new_foogen() -> Self {
        Self::new()
    }
}

impl Facade<BarGen> {
    fn new_bargen() -> Self {
        Self::new()
    }
}
查看更多
登录 后发表回答