Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Обобщённые реализации трейтов (blanket)

Если трейт локальный, мы можем реализовать его для любого количества типов. Как далеко можно зайти?

// Copyright 2025 Google LLC
// SPDX-License-Identifier: Apache-2.0

pub trait PrettyPrint {
    fn pretty_print(&self);
}

// Обобщённая реализация! Если что-то реализует Display, то оно реализует
// PrettyPrint.
impl<T> PrettyPrint for T
where
    T: std::fmt::Display,
{
    fn pretty_print(&self) {
        println!("{self}")
    }
}
  • Субъектом реализации трейта в месте его определения может быть что угодно, включая T без ограничений.

    С T, о котором мы ничего не знаем, ничего нельзя сделать, поэтому такое встречается редко.

  • Условные обобщённые реализации гораздо полезнее, и вы с большей вероятностью будете встречать и писать их сами.

    Такие реализации содержат ограничение на трейт, например impl <T: Display> ToString for T {...}

    В примере выше у нас есть обобщённая реализация для всех типов, реализующих Display. Реализация получает из ограничений трейта одну информацию: тип реализует Display::fmt.

    Этого достаточно, чтобы написать реализацию красивого вывода в консоль.

  • Будьте осторожны с такими реализациями: они могут помешать пользователям ниже по цепочке зависимостей реализовать более подходящую.

    Выше пример не написан для Debug, потому что тогда почти все типы реализовали бы PrettyPrint, а Debug семантически не похож на Display: он предназначен для отладочного вывода, а не для того, что удобно читать человеку.

Справка:

  • https://doc.rust-lang.org/reference/glossary.html#blanket-implementation