Implementing a trait for reference and non reference types causes conflicting implementations

前端 未结 2 659
迷失自我
迷失自我 2021-01-14 02:46

I\'m trying to create a trait and provide one implementation for all non-reference types, and another for all reference types.

This fails to compile:



        
2条回答
  •  时光说笑
    2021-01-14 03:18

    As you have learned, a generic T can be anything¹, so the Foo impls overlap (conflict) whenever T in the first impl is &'a mut U, because the second impl also covers that case (when T is U).

    The Clone version works simply because &mut references never implement Clone, so there's no overlap between T where T: Clone and &'a mut T.² If you try to implement Bar for immutable (&) references, you will have a conflict again, because immutable references do implement Clone.

    [H]ow can I make it work without it?

    If by "it" you mean one implementation for reference types and another, different one for non-reference types, that's not possible in Rust for the same reason you can't implement a trait one way for structs and another way for enums: there simply is no way to express it (in current Rust).

    One common pattern that might work for you is implementing your trait individually for whatever non-reference types you need, and then adding a "blanket impl" that covers any reference to a type for which the trait is already implemented, e.g.:

    impl Foo for u32 { ... }
    impl Foo for i32 { ... }
    impl<'a, T> Foo for &'a T where T: Foo + 'a { ... }
    impl<'a, T> Foo for &'a mut T where T: Foo + 'a { ... }
    

    ¹ Well, anything that is Sized, at least. You have to add ?Sized if that's not what you want.

    ² The where T: Clone + 'static clause doesn't matter, because &'a mut T will never be Clone whether T itself is or not.

提交回复
热议问题