简体   繁体   English

在 trait 中定义一个方法,返回 Self 的默认实现

[英]Define a method in trait returning a default implementation of Self

I would like to have the following functionality我想拥有以下功能

trait Policy {
    fn eval(&self, k: u32) -> bool;

    fn default() -> Box<dyn Policy>
    where
        Self: Sized,
    {
        Box::new(MaxPolicy { max: 2 })
    }
}

struct MaxPolicy {
    max: u32,
}

impl Policy for MaxPolicy {
    fn eval(&self, k: u32) -> bool {
        println!("MaxPolicy");
        k < self.max
    }
}

#[test]
fn max_policy() {
    let p = MaxPolicy { max: 2 };
    assert!(!p.eval(3));
}

#[test]
fn default_policy() {
    let p = Policy::default();
    assert!(!p.eval(3));
}

( Playground ) 游乐场

This does not compile:这不会编译:

error[E0283]: type annotations needed
  --> src/lib.rs:31:13
   |
4  |     fn default() -> Box<dyn Policy>
   |        -------
5  |     where
6  |         Self: Sized,
   |               ----- required by this bound in `Policy::default`
...
31 |     let p = Policy::default();
   |             ^^^^^^^^^^^^^^^ cannot infer type
   |
   = note: cannot resolve `_: Policy`

Would it possible to alter the approach to make it work?是否有可能改变方法以使其发挥作用? Is this even possible for trait objects to have a method returning some implementation of Self ?这甚至可能让 trait 对象有一个方法返回Self的一些实现吗? If not, why not?如果不是,为什么不呢?

Implement default on the trait object type, not on the trait:在特征 object 类型上实现default ,而不是在特征上:

trait Policy {
    fn eval(&self, k: u32) -> bool;
}

impl dyn Policy {
    fn default() -> Box<Self> {
        Box::new(MaxPolicy { max: 2 })
    }
}

See also:也可以看看:

I constructed a workaround which has a similar nice API我构建了一个解决方法,它具有类似的漂亮 API

trait Policy {
    fn eval(&self, k: u32) -> bool;
}

struct MaxPolicy {
    max: u32,
}

impl Policy for MaxPolicy {
    fn eval(&self, k: u32) -> bool {
        println!("MaxPolicy");
        k < self.max
    }
}

struct MinPolicy {
    min: u32,
}

impl Policy for MinPolicy {
    fn eval(&self, k: u32) -> bool {
        println!("MinPolicy");
        k > self.min
    }
}

enum PolicyEnum {
    Custom(Box<dyn Policy>),
    Default,
}

impl PolicyEnum {
    const DEFAULT: MaxPolicy = MaxPolicy { max: 4 };
}

impl Policy for PolicyEnum {
    fn eval(&self, k: u32) -> bool {
        match self {
            PolicyEnum::Custom(p) => p.eval(k),
            PolicyEnum::Default => Self::DEFAULT.eval(k),
        }
    }
}

Playground 操场

With that, it's possible to do:有了它,就可以做到:

#[test]
fn default() {
    let p = PolicyEnum::Default;

    assert!(p.eval(3));
}

#[test]
fn custom() {
    let p = PolicyEnum::Custom(Box::new(MinPolicy{min: 4}));

    assert!(p.eval(5));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM