如何使特征的实现更通用

huangapple go评论62阅读模式
英文:

How to make implementations of traits more generic

问题

You can use Rust's generic trait implementations to avoid having to implement Widget for each possible numeric type explicitly. Here's an example of how you can do it:

impl<T: Numeric> Widget<T> for NumberWidget<T> {
    fn common(&self) -> &Common {
        &self.common
    }

    fn value(&self) -> &T {
        &self.value
    }

    fn value_mut(&mut self) -> &mut T {
        &mut self.value
    }
}

This code defines a generic implementation of the Widget trait for NumberWidget<T> where T is any type that satisfies the Numeric trait bound. This way, you can use NumberWidget with various numeric types without the need for explicit implementations for each type.

英文:

So I have a trait called "Widget" which is quite simple:

pub trait Widget&lt;T&gt; {
    fn common(&amp;self) -&gt; &amp;Common;
    fn value(&amp;self) -&gt; &amp;T;
    fn value_mut(&amp;mut self) -&gt; &amp;mut T;
}

Other than the custom struct Common (defined elsewhere), it should be clear that the Widget trait simply specifies that an immutable or mutable reference can be returned using .value() and .value_mut functions, and this will be of the same type as the Widget itself (T).

So, for example, I have a "NumberWidget", like this...

pub struct NumberWidget&lt;T&gt; {
    common: Common,
    value: T,
    range: RangeInclusive&lt;T&gt;,
}

impl&lt;T: Numeric&gt; NumberWidget&lt;T&gt; {
    pub fn new(
     ...etc.
 

...which is constrained by the trait bound Numeric - it can only apply to primitive numbers.

I want NumberWidget to satisfy the trait Widget, of course. But I cannot simply write...

 impl Widget for NumberWidget {

Because both Widget and NumberWidget need a generic argument.

So let's say I want to have integer and float versions of "NumberWidget". The only way I have so far which works and compiles is to implement both explicitly:

impl Widget&lt;f64&gt; for NumberWidget&lt;f64&gt; {
    fn common(&amp;self) -&gt; &amp;Common {
        &amp;self.common
    }
    fn value(&amp;self) -&gt; &amp;f64 {
        &amp;self.value
    }
    fn value_mut(&amp;mut self) -&gt; &amp;mut f64 {
        &amp;mut self.value
    }
}

impl Widget&lt;i64&gt; for NumberWidget&lt;i64&gt; {
    fn common(&amp;self) -&gt; &amp;Common {
        &amp;self.common
    }
    fn value(&amp;self) -&gt; &amp;i64 {
        &amp;self.value
    }
    fn value_mut(&amp;mut self) -&gt; &amp;mut i64 {
        &amp;mut self.value
    }
}

This is fine for just two variations, but it's already more duplication than I feel comfortable with. I guess I'm looking for something like:

impl Widget&lt;T: Numeric&gt; for NumberWidget&lt;T&gt;

But this is not valid:

trait takes 1 generic argument but 0 generic arguments were supplied
expected 1 generic argument

associated type bounds are unstable
see issue #52662 &lt;https://github.com/rust-lang/rust/issues/52662&gt; for more information

associated type bindings are not allowed here
associated type not allowed here

cannot find type `T` in this scope

.etc. etc.

Is there a way to construct instances such as NumberWidget&lt;i64&gt;, NumberWidget&lt;usize&gt;, NumberWidget&lt;f32&gt;, etc. without having to implement impl NumberWidget&lt;i64&gt; for Widget&lt;i64&gt;, etc. explicitly for every possible Numeric type?

答案1

得分: 2

你只是把类型参数放错了地方,你要找的是这样的:

impl<T: Numeric> Widget<T> for NumberWidget<T> {
//  ^^^^^^^^^^^^ 类型参数应该放在 impl 块自身上
    fn common(&self) -> &Common {
        &self.common
    }
    fn value(&self) -> &T {
        &self.value
    }
    fn value_mut(&mut self) -> &mut T {
        &mut self.value
    }
}
英文:

You've merely placed the type parameter in the wrong place, you're looking for this:

impl&lt;T: Numeric&gt; Widget&lt;T&gt; for NumberWidget&lt;T&gt; {
//  ^^^^^^^^^^^^ The type parameter goes on the impl block itself
    fn common(&amp;self) -&gt; &amp;Common {
        &amp;self.common
    }
    fn value(&amp;self) -&gt; &amp;T {
        &amp;self.value
    }
    fn value_mut(&amp;mut self) -&gt; &amp;mut T {
        &amp;mut self.value
    }
}

huangapple
  • 本文由 发表于 2023年5月10日 20:47:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76218618.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定