Menu
Coddy logo textTech

Синтаксис ограничений трейтов

Часть раздела Объектно-ориентированное программирование путешествия по Rust на Coddy. Урок 40 из 61.

До сих пор вы учились определять трейты и реализовывать их для структур. Вы также работали с generic, чтобы писать гибкий код. Теперь пришло время объединить эти концепции: использовать трейты, чтобы ограничить типы, которые generic function может accept.

Рассмотрим generic function, которой необходимо вызвать конкретный method для своего параметра. Без каких-либо ограничений Rust не гарантирует, что тип T имеет этот method:

fn print_info<T>(item: T) {
    println!("{}", item.summarize());  // Ошибка! У T может не быть summarize()
}

Решение — это ограничение трейта. Добавив : TraitName после обобщённого параметра, вы сообщаете Rust, что T должен реализовывать этот трейт:

trait Summary {
    fn summarize(&self) -> String;
}

fn print_info<T: Summary>(item: T) {
    println!("{}", item.summarize());  // Теперь Rust знает, что этот метод существует
}

Синтаксис <T: Summary> читается как «T — это любой тип, который implements Summary». Теперь function принимает только типы, которые have требуемое поведение. Если попытаться передать тип, который не implements Summary, компилятор отклонит его с понятной ошибкой.

Этот шаблон эффективен, потому что позволяет писать generic-код, который при этом сохраняет доступ к определённой функциональности. Ваша function остаётся гибкой: она работает с любым типом, но только с теми типами, которые предоставляют нужное вам поведение.

challenge icon

Задание

Легко

Давайте создадим систему уведомлений, которая использует ограничения трейтов, чтобы гарантировать отправку только правильно отформатированных сообщений! Вы создадите generic function, принимающую любой тип, реализующий определённый трейт, и продемонстрируете, как ограничения трейтов ограничивают generic параметры.

Вы организуете код в двух файлах:

  • notification.rs: Определите публичный трейт Notify с method под названием message, который принимает &self и возвращает String. Затем создайте две публичные структуры, реализующие этот трейт:
    • Email: с публичным полем subject (String). Его message method должен возвращать Email: {subject}
    • SMS: с публичным полем content (String). Его message method должен возвращать SMS: {content}
    Наконец, создайте публичную generic function под названием send_notification, которая принимает любой тип T, реализующий трейт Notify. Эта function должна вывести result вызова message() для item.
  • main.rs: Подключите модуль уведомлений и используйте предоставленные inputs, чтобы создать экземпляры Email и SMS. Вызовите send_notification для каждого из них, чтобы продемонстрировать, что ваша generic function работает с любым типом, реализующим Notify.

Ключевая идея заключается в том, что send_notification не знает конкретный тип, который он получает. Он знает только, что этот тип может создать сообщение. Ограничение трейта T: Notify гарантирует эту возможность.

Ваш результат должен показать отправку обоих уведомлений:

Email: {subject}
SMS: {content}

Например, с inputs Meeting Tomorrow и On my way!:

Email: Meeting Tomorrow
SMS: On my way!

Вы получите два inputs: тему email и content SMS.

Попробуйте сами

mod notification;

use notification::{Email, SMS, send_notification};

fn main() {
    // Чтение входных данных
    let mut subject = String::new();
    std::io::stdin().read_line(&mut subject).expect("Failed to read line");
    let subject = subject.trim().to_string();
    
    let mut content = String::new();
    std::io::stdin().read_line(&mut content).expect("Failed to read line");
    let content = content.trim().to_string();
    
    // TODO: Создать экземпляр Email с subject
    
    // TODO: Создать экземпляр SMS с content
    
    // TODO: Вызвать send_notification с email
    
    // TODO: Вызвать send_notification с sms
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Rust