Should trait bounds be duplicated in struct and impl?

后端 未结 2 1071
予麋鹿
予麋鹿 2020-12-06 09:45

The following code uses a struct with generic type. While it\'s implementation is only valid for the given trait bound, the struct can be defined with or without the same bo

相关标签:
2条回答
  • 2020-12-06 10:06

    Trait bounds that apply to every instance of the struct should be applied to the struct:

    struct IteratorThing<I>
    where
        I: Iterator,
    {
        a: I,
        b: Option<I::Item>,
    }
    

    Trait bounds that only apply to certain instances should only be applied to the impl block they pertain to:

    struct Pair<T> {
        a: T,
        b: T,
    }
    
    impl<T> Pair<T>
    where
        T: std::ops::Add<T, Output = T>,
    {
        fn sum(self) -> T {
            self.a + self.b
        }
    }
    
    impl<T> Pair<T>
    where
        T: std::ops::Mul<T, Output = T>,
    {
        fn product(self) -> T {
            self.a * self.b
        }
    }
    

    to conform to the DRY principle

    The redundancy will be removed by RFC 2089:

    Eliminate the need for “redundant” bounds on functions and impls where those bounds can be inferred from the input types and other trait bounds. For example, in this simple program, the impl would no longer require a bound, because it can be inferred from the Foo<T> type:

    struct Foo<T: Debug> { .. }
    impl<T: Debug> Foo<T> {
      //    ^^^^^ this bound is redundant
      ...
    }
    
    0 讨论(0)
  • 2020-12-06 10:18

    It really depends on what the type is for. If it is only intended to hold values which implement the trait, then yes, it should have the trait bound e.g.

    trait Child {
        fn name(&self);
    }
    
    struct School<T: Child> {
        pupil: T,
    }
    
    impl<T: Child> School<T> {
        fn role_call(&self) -> bool {
            // check everyone is here
        }
    }
    

    In this example, only children are allowed in the school so we have the bound on the struct.

    If the struct is intended to hold any value but you want to offer extra behaviour when the trait is implemented, then no, the bound shouldn't be on the struct e.g.

    trait GoldCustomer {
        fn get_store_points(&self) -> i32;
    }
    
    struct Store<T> {
        customer: T,
    }
    
    impl<T: GoldCustomer> Store {
        fn choose_reward(customer: T) {
            // Do something with the store points
        }
    }
    

    In this example, not all customers are gold customers and it doesn't make sense to have the bound on the struct.

    0 讨论(0)
提交回复
热议问题