Menu
Coddy logo textTech

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

Часть раздела Object Oriented Programming путешествия по Rust на Coddy — урок 32 из 61.

Реализации по умолчанию удобны, но иногда типу требуется поведение, отличное от стандартного. В таких случаях вы можете переопределить поведение по умолчанию, предоставив собственную реализацию в блоке 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 в сети.

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

challenge icon

Задание

Легко

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

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

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

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

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

Alert: Something happened!
URGENT: {message}

Например, при входных данных Server is down!:

Alert: Something happened!
URGENT: Server is down!

Вы получите одни входные данные: сообщение для срочного оповещения (urgent alert).

Шпаргалка

Вы можете переопределить реализации типажа по умолчанию, предоставив собственную реализацию в блоке 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)
    }
}

let bot = Robot { id: 42 };
println!("{}", bot.greet());  // BEEP BOOP. Unit 42 online.

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

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

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Проверьте себя

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

Все уроки раздела Object Oriented Programming