How to exclude a type from generic trait implementation?

#1

I need to implement a trait for Vec<T> but Vec<u8> needs some special treatment. How can I handle this special case?

trait MyTrait { }

impl<T> MyTrait for Vec<T> /* where T: !u8 */ { }

impl MyTrait for Vec<u8> { }

results in

error[E0119]: conflicting implementations of trait `MyTrait` for type `std::vec::Vec<u8>`:

I guess that https://github.com/rust-lang/rust/issues/31844 will allow this some day but I wonder if there is a workaround for my case readily available.

I tried to filter the types by TypeId::of::<T>() == TypeId::of::<u8> but this is restricted to 'static lifetimes only. I also tried to filter by mem::size_of == 1 but this gives my false positives on bool at least.

I don’t mind to implement the trait for all built-in primitive types if that helps, but I don’t want to implement this for every type.

0 Likes

#2

This is not currently possible to do in a generic way; you should use a macro and write out all the impls you want.

0 Likes

#3

I just found a workaround that works for me:

pub trait MyTrait {
    fn is_special_case() -> bool { false }
}

This gets overridden with true for u8 only. Even though this is a run-time check, the compiler should optimize this away.

1 Like

#4

You may replace that with an associated const to elevate part of that check to compile time:

trait MyTrait {
    const IS_SPECIAL_CASE: bool = false;
}

impl MyTrait for Vec<u8> {
    const IS_SPECIAL_CASE: bool = true;
}

I expect the compiler to optimize the fn in the same way, but associated consts just seem like a better way.

2 Likes

#5

Oh, I didn’t know that consts can be overwritten. That’s definitely better than a (const) method.
Thank you!

0 Likes