Menu
Coddy logo textTech

Методы в перечислениях

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

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

Вот как добавить метод к перечислению Message из предыдущего урока:

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
}

impl Message {
    fn describe(&self) -> String {
        match self {
            Message::Quit => String::from("Quit signal"),
            Message::Move { x, y } => format!("Move to ({}, {})", x, y),
            Message::Write(text) => format!("Message: {}", text),
        }
    }
}

Блок impl Message работает точно так же, как и для структур. Метод принимает &self для доступа к экземпляру перечисления. Внутри метода вы используете match, чтобы определить, с каким вариантом вы имеете дело, и вернуть соответствующий результат.

Вызов метода выглядит одинаково независимо от того, какой вариант у вас есть:

fn main() {
    let m1 = Message::Quit;
    let m2 = Message::Move { x: 10, y: 20 };
    
    println!("{}", m1.describe());  // Сигнал выхода
    println!("{}", m2.describe());  // Перемещение в (10, 20)
}

Этот паттерн очень эффективен, потому что вызывающему коду не нужно знать, какой именно вариант он использует — он просто вызывает метод, а перечисление (enum) берет на себя остальное. Поведение меняется в зависимости от варианта, но интерфейс остается неизменным.

challenge icon

Задание

Легко

Давайте создадим систему светофора, которая использует перечисление (enum) с методами для описания текущего состояния сигнала. Каждый цвет светофора будет содержать информацию о том, как долго он длится, а метод будет предоставлять понятное человеку описание.

Вы создадите два файла для организации вашего кода:

  • traffic.rs: Определите публичное перечисление TrafficLight с тремя вариантами:
    • Red — содержит u32, представляющее секунды ожидания
    • Yellow — содержит u32, представляющее секунды ожидания
    • Green — содержит u32, представляющее секунды движения
    Затем реализуйте метод status, который возвращает String с описанием сигнала. Используйте match внутри метода для обработки каждого варианта и включите длительность в сообщение.
  • main.rs: Подключите ваш модуль traffic, создайте экземпляры каждого варианта светофора и вызовите метод status для каждого из них, чтобы вывести описания.

Метод status должен возвращать сообщения строго в следующих форматах:

  • Для Red: Stop for {seconds} seconds
  • Для Yellow: Caution for {seconds} seconds
  • Для Green: Go for {seconds} seconds

Ваш вывод должен отображать статус каждого сигнала на отдельной строке:

Stop for {seconds} seconds
Caution for {seconds} seconds
Go for {seconds} seconds

Например, при красном сигнале в 30 секунд, желтом в 5 секунд и зеленом в 25 секунд, вывод будет следующим:

Stop for 30 seconds
Caution for 5 seconds
Go for 25 seconds

Вы получите три входных значения: длительность красного сигнала, длительность желтого сигнала и длительность зеленого сигнала.

Шпаргалка

Перечисления могут иметь методы, определенные в impl блоках, точно так же, как и структуры:

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
}

impl Message {
    fn describe(&self) -> String {
        match self {
            Message::Quit => String::from("Quit signal"),
            Message::Move { x, y } => format!("Move to ({}, {})", x, y),
            Message::Write(text) => format!("Message: {}", text),
        }
    }
}

Методы принимают &self для доступа к экземпляру перечисления и используют match для обработки различных вариантов:

let m1 = Message::Quit;
let m2 = Message::Move { x: 10, y: 20 };

println!("{}", m1.describe());  // Сигнал выхода
println!("{}", m2.describe());  // Перемещение в (10, 20)

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

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

mod traffic;

use traffic::TrafficLight;

fn main() {
    // Чтение входных данных для длительности
    let mut red_input = String::new();
    std::io::stdin().read_line(&mut red_input).expect("Failed to read line");
    let red_duration: u32 = red_input.trim().parse().expect("Invalid number");

    let mut yellow_input = String::new();
    std::io::stdin().read_line(&mut yellow_input).expect("Failed to read line");
    let yellow_duration: u32 = yellow_input.trim().parse().expect("Invalid number");

    let mut green_input = String::new();
    std::io::stdin().read_line(&mut green_input).expect("Failed to read line");
    let green_duration: u32 = green_input.trim().parse().expect("Invalid number");

    // TODO: Создать экземпляры каждого варианта TrafficLight с введенными длительностями

    // TODO: Вызвать метод status для каждого светофора и вывести результат
}
quiz iconПроверьте себя

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

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