Почему возможно реализовать черту как для "T: Display", так и "str"?

Пока нет никакой специализации в стабильной Rust, так что это не работает:

trait X {}

impl<T> X for T {}
impl X for u32 {}  // conflicting implementation

Никаких сюрпризов нет: X реализован для любого типа T и мы не можем реализовать его снова для u32.

Удивительно, но следующий фрагмент успешно компилируется:

use std::fmt::Display;

pub trait Show {}

impl<T: Display> Show for T {}

impl Show for str {}

// These impls would cause "conflicting implementation" errors:
// impl<'a> Show for &'a str
// impl Show for String

fn main() {}

Я бы не ожидал, что этот код будет компилироваться, потому что Display реализован для str, поэтому универсальный impl должен реализовать Show for str и конфликтовать с конкретным им.

Почему impl Show for str не конфликтует с impl<T: Display> Show for T?

Ответ 1

Ограниченный <T: Display> неявно предполагает, что T должен быть размерным типом. Однако str не поддерживается. Поэтому два имплана не конфликтуют друг с другом.

Если вам нужно также покрывать нестандартные типы, такие как str, вам нужно уменьшить требование Sized, добавив T:?Sized:

impl<T: Display + ?Sized> Show for T {}
//              ^~~~~~~~