解答

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

#![allow(dead_code)]

#[derive(Debug)]
/// An event in the elevator system that the controller must react to.
enum Event {
    /// A button was pressed.
    ButtonPressed(Button),

    /// The car has arrived at the given floor.
    CarArrived(Floor),

    /// The car's doors have opened.
    CarDoorOpened,

    /// The car's doors have closed.
    CarDoorClosed,
}

/// A floor is represented as an integer.
type Floor = i32;

/// A direction of travel.
#[derive(Debug)]
enum Direction {
    Up,
    Down,
}

/// A user-accessible button.
#[derive(Debug)]
enum Button {
    /// A button in the elevator lobby on the given floor.
    LobbyCall(Direction, Floor),

    /// A floor button within the car.
    CarFloor(Floor),
}

/// The car has arrived on the given floor.
fn car_arrived(floor: i32) -> Event {
    Event::CarArrived(floor)
}

/// The car doors have opened.
fn car_door_opened() -> Event {
    Event::CarDoorOpened
}

/// The car doors have closed.
fn car_door_closed() -> Event {
    Event::CarDoorClosed
}

/// A directional button was pressed in an elevator lobby on the given floor.
fn lobby_call_button_pressed(floor: i32, dir: Direction) -> Event {
    Event::ButtonPressed(Button::LobbyCall(dir, floor))
}

/// A floor button was pressed in the elevator car.
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 の enum バリアントはデータを持てます。CarArrived(Floor) は整数を持ち、ButtonPressed(Button) はネストされた Button enum を持ちます。これにより、Event は型安全な方法で豊富な状態の集合を表現できます。
  • 型エイリアス: type Floor = i32i32 に意味的な名前を与えます。これにより可読性は向上しますが、コンパイラにとって Floor は依然として単なる i32 です。
  • #[derive(Debug)]: この属性は、{:?} を使って列挙型を出力用にフォーマットするコードを自動生成するために使います。これがなければ、fmt::Debug トレイトを手動で実装する必要があります。
  • ネストされた列挙型: Button enumEvent::ButtonPressed の中にネストされています。この階層構造は、複雑なドメインをモデル化するために Rust でよく使われます。
  • Event::CarDoorOpened は「ユニットバリアント」(データを持たない)である一方、Event::CarArrived は「タプルバリアント」であることに注意してください。
  • Button を別個の enum にしている理由について議論してもよいでしょう。EventLobbyCallButtonPressedCarFloorButtonPressed のバリアントを直接持たせることもできます。どちらも有効ですが、関連する概念(ボタンなど)をまとめることで、コードをよりすっきりさせられます。