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

Решение

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

#![allow(dead_code)]

#[derive(Debug)]
/// Событие в системе лифта, на которое должен реагировать контроллер.
enum Event {
    /// Была нажата кнопка.
    ButtonPressed(Button),

    /// Кабина прибыла на указанный этаж.
    CarArrived(Floor),

    /// Двери кабины открылись.
    CarDoorOpened,

    /// Двери кабины закрылись.
    CarDoorClosed,
}

/// Этаж представлен целым числом.
type Floor = i32;

/// Направление движения.
#[derive(Debug)]
enum Direction {
    Up,
    Down,
}

/// Кнопка, доступная пользователю.
#[derive(Debug)]
enum Button {
    /// Кнопка в холле лифта на указанном этаже.
    LobbyCall(Direction, Floor),

    /// Кнопка этажа внутри кабины.
    CarFloor(Floor),
}

/// Кабина прибыла на указанный этаж.
fn car_arrived(floor: i32) -> Event {
    Event::CarArrived(floor)
}

/// Двери кабины открылись.
fn car_door_opened() -> Event {
    Event::CarDoorOpened
}

/// Двери кабины закрылись.
fn car_door_closed() -> Event {
    Event::CarDoorClosed
}

/// Была нажата кнопка направления в холле лифта на указанном этаже.
fn lobby_call_button_pressed(floor: i32, dir: Direction) -> Event {
    Event::ButtonPressed(Button::LobbyCall(dir, floor))
}

/// Была нажата кнопка этажа в кабине лифта.
fn car_floor_button_pressed(floor: i32) -> Event {
    Event::ButtonPressed(Button::CarFloor(floor))
}

fn main() {
    println!(
        "A ground floor passenger has pressed the up button: {:?}",
        lobby_call_button_pressed(0, Direction::Up)
    );
    println!("The car has arrived on the ground floor: {:?}", car_arrived(0));
    println!("The car door opened: {:?}", car_door_opened());
    println!(
        "A passenger has pressed the 3rd floor button: {:?}",
        car_floor_button_pressed(3)
    );
    println!("The car door closed: {:?}", car_door_closed());
    println!("The car has arrived on the 3rd floor: {:?}", car_arrived(3));
}
  • Перечисления с данными: варианты перечислений Rust могут содержать данные. CarArrived(Floor) хранит целое число, а ButtonPressed(Button) хранит вложенное перечисление Button. Так Event может представлять богатый набор состояний безопасным для типов способом.
  • Псевдонимы типов: type Floor = i32 задаёт семантическое имя для i32. Это повышает читаемость, но для компилятора Floor по-прежнему остаётся просто i32.
  • #[derive(Debug)]: этот атрибут автоматически генерирует код, который форматирует перечисления при выводе через {:?}. Без него пришлось бы вручную реализовать трейт fmt::Debug.
  • Вложенные перечисления: перечисление Button вложено в Event::ButtonPressed. Такая иерархическая структура распространена в Rust для моделирования сложных предметных областей.
  • Обратите внимание, что Event::CarDoorOpened — это «вариант-единица» (он не содержит данных), а Event::CarArrived — «кортежный вариант».
  • Можно обсудить, почему Button — отдельное перечисление, а не просто варианты LobbyCallButtonPressed и CarFloorButtonPressed в Event. Оба подхода корректны, но группировка связанных понятий (например, кнопок) может сделать код чище.