Menu
Coddy logo textTech

Переопределение реализаций по умолчанию

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

Стандартные реализации удобны, но иногда типу требуется поведение, отличающееся от стандартного. В таких случаях можно override стандартную реализацию, предоставив собственную реализацию в блоке impl.

Просто определите метод с той же сигнатурой, но добавьте свою пользовательскую логику:

trait Greet {
    fn greet(&self) -> String {
        String::from("Hello there!")
    }
}

struct Robot {
    id: u32,
}

impl Greet for Robot {
    fn greet(&self) -> String {
        format!("BEEP BOOP. Unit {} online.", self.id)
    }
}

Хотя Greet предоставляет метод greet по умолчанию, Robot полностью заменяет его собственной версией. Когда вы вызываете greet() у Robot, Rust использует пользовательскую реализацию:

let bot = Robot { id: 42 };
println!("{}", bot.greet());  // БИП БУП. Юнит 42 онлайн.

Это даёт вам гибкость: типам, которых устраивает default, не нужно ничего писать, а типы, которым требуется специализированное поведение, могут переопределить только те method, которые им нужны. Трейт по-прежнему гарантирует, что у каждого реализующего типа доступен method.

challenge icon

Задание

Легко

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

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

  • notifiable.rs: Define публичный трейт Notifiable с notify(&self) -> String method, у которого есть реализация по умолчанию, возвращающая "Alert: Something happened!".
  • alerts.rs: Создайте две публичные структуры, которые по-разному implement ваш трейт:
    • GenericAlert: unit-структура, использующая уведомление по умолчанию (пустой impl block)
    • UrgentAlert: структура с публичным полем message типа String, которая override значение по умолчанию и возвращает "URGENT: {message}", где {message} — её сохранённое сообщение
  • main.rs: Объедините модули и продемонстрируйте оба варианта поведения. Создайте GenericAlert и UrgentAlert, используя предоставленные input, затем выведите их уведомления.

Главная идея заключается в том, что GenericAlert бесплатно получает поведение по умолчанию, тогда как UrgentAlert предоставляет собственную специализированную версию, определяя method в своём impl block.

Ваш вывод должен соответствовать этому формату:

Alert: Something happened!
URGENT: {message}

Например, при input Server is down!:

Alert: Something happened!
URGENT: Server is down!

Вы получите один input: сообщение для срочного оповещения.

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

mod notifiable;
mod alerts;

use alerts::{GenericAlert, UrgentAlert};
use notifiable::Notifiable;

fn main() {
    // Считать ввод для сообщения срочного оповещения
    let mut input = String::new();
    std::io::stdin().read_line(&mut input).expect("Failed to read line");
    let message = input.trim().to_string();

    // TODO: Создать экземпляр GenericAlert

    // TODO: Создать экземпляр UrgentAlert с введённым сообщением

    // TODO: Вывести уведомление от GenericAlert

    // TODO: Вывести уведомление от UrgentAlert
}
quiz iconПроверьте себя

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

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

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