Перечисления Enum

Последнее обновление: 01.06.2024

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

Формальное определение перечисления:

enum название_перечисления
{
вариант1,
вариант2,
...........
вариантN
}

После названия перечисления в фигурных скобках через запятую перечисляются варианты перечисления.

Например, определим перечисление, которое назовем OperationType и которое будет представлять арифметические операции:

enum OperationType{
	
	Add,		// сложение
	Subtract,	// вычитание
	Multiply,	// умножение
	Divide		// деление
}

Для обращения к варианту перечисления указывается название перечисления и через два двоеточия его вариант:

название_перечисления::вариант

Например, мы можем определить переменную перечисления:

let op = OperationType::Multiply;

В данном случае переменная op представляет вариант OperationType::Multiply.

Как было сказано в начале, перечисления удобны для определения состояний. И в зависимости от текущего состояния выполняется то или иное действие. Например:

fn main(){
	// определяем переменную перечисления OperationType
    let op = OperationType::Multiply;
	
	match op
	{
		OperationType::Add => println!("Сложение"),
		OperationType::Subtract => println!("Вычитание"),
		OperationType::Multiply => println!("Умножение"),
		OperationType::Divide => println!("Деление")
	}
}
enum OperationType{
	
	Add,		// сложение
	Subtract,	// вычитание
	Multiply,	// умножение
	Divide		// деление
}

Здесь в конструкции match проверяется состояние переменной op. В зависимости от значения этой переменной выводится то или иное сообщение на консоль. Поскольку эта переменная равна OperationType::Multiply, то будет выполняться выражение:

OperationType::Multiply => println!("Умножение"),

Если в будущем потребуется изменить значение переменной перечисления, то такая переменная должна быть определена с помощью ключевого слова mut. Например, применим перечисление OperationType для выполнения арифметических операций:

fn main(){
 
	let a = 10; 
	let b = 5;
    let mut op = OperationType::Add;
	
	let mut result = get_result(a, b, op);
	println!("result = {}", result);		// result = 15
	
	// меняем операцию
	op = OperationType::Subtract;
	result = get_result(a, b, op);			// result = 5
	println!("result = {}", result);		
	
	// передаем еще одно значение
	result = get_result(a, b, OperationType::Divide);
	println!("result = {}", result);		// result = 2
}
fn get_result(x: i32, y: i32, op: OperationType) -> i32{

	match op
	{
		OperationType::Add => x + y,
		OperationType::Subtract => x - y,
		OperationType::Multiply => x * y,
		OperationType::Divide => x / y
	}
}
enum OperationType{
	
	Add,		// сложение
	Subtract,	// вычитание
	Multiply,	// умножение
	Divide		// деление
}

В данном случае все арифметические операции вынесены в отдельную функцию get_result(), которая в качестве параметров принимает два числа (над которыми выполняется операция) и значение перечисления OperationType, которое указывает, какую именно операцию надо выполнять. Результат операции возвращается функцией.

В функции main вызывается функция get_result(), в которую передаются различные типы операций, и соответственно функция будет возвращать различный результат:

result = 15
result = 5
result = 2

Установка типа значений перечисления

К вариантам перечисления можно прикрепить некоторые значения. Выше варианты перечисления OperationType не имели никаких данных, но мы можем их определить. Например:

enum DayTime{
	
	Morning(String),
	Evening(String)
}

Здесь с обоими вариантами перечисления DayTime ассоциирован кортеж с одним значением типа String, то есть по сути варианты перечисления могут хранить некоторую строку. А это значит, что при создании объекта этого перечисления нам надо передать ему кортеж с одной строкой:

let dt = DayTime::Morning("Доброе утро".to_string());

Значение передается в скобках после названия варианта. Поскольку в данном случае вариант DayTime::Morning представляет тип String, то переданная строка преобразуется с помощью метода to_string() к типу String.

При этом с разными вариантами перечисления может быть ассоциировано различное количество значений. Далее будет рассмотрен синтасис шаблонов, который позволяет получить и использовать значения, хранимые в вариантах перечисления, а пока вкратце посмотрим еще одни пример использования значений в перечислениях:

fn main(){
    let op1 = OperationType::Sum(5, 6);
    let op2 = OperationType::Negation(7);
    let op3 = OperationType::Zero;

    print_op(op1);
    print_op(op2);
    print_op(op3);
}
fn print_op(op: OperationType){

    match op {

        OperationType::Sum(x, y) => println!("Сложение {x} и {y}"),
        OperationType::Negation(n) => println!("Умножение на -1 числа {n}"),
        OperationType::Zero => println!("Ноль")
    }
}

enum OperationType{
     
    Sum(i32, i32),  // сложение
    Negation(i32),   // умножение на -1
    Zero,           // просто возвращаем 0
}

Здесь перечисление OperationType имеет три варианта. Первый вариант - Sum, который представляет условное сложение, принимает кортеж с двумя числами i32. Вариант Negation принимает одно число, а с вариантом Zero вообще не ассоциировано никаких значений.

В функции print_op выводим информацию о варианте перечисления на консоль. Для получения ассоциированных с вариантом данных в конструкции match указывается вариант, а в скобках определяется кортеж с переменными для каждого значения:

OperationType::Sum(x, y) => println!("Сложение {x} {y}")

Далее мы подробнее рассмотрим подобный синтаксис. В итоге программа даст нам следующий консольный вывод:

Сложение 5 и 6
Умножение на -1 числа 7
Ноль

Мы также можем определять значения вариантов перечислений в виде структур:

fn main(){
    let user1 = Users::Person("Tom".to_string());
    let user2 = Users::Employee{name: "Bob".to_string(), company: "Rust Foundation".to_string()};

    print_user(&user1);
    print_user(&user2);
}
fn print_user(user: &Users){

    match user {

        Users::Person(name) => println!("Person {name}"),
        Users::Employee{name: emp_name, company: emp_company} => 
            println!("Employee {emp_name} ({emp_company})")
    }
}
enum Users{

    Person(String),
    Employee {name:String, company:String}
}

Здесь в перечислении Users есть два варианта: Person(простой человек) и Employee (работник). Если с Person ассоциирован кортеж с одинм значением, то с Employee - структура с двумя полями - name и company. Соответственно при определении значения этого варианта надо определить структуру:

let user2 = Users::Employee{name: "Bob".to_string(), company: "Rust Foundation".to_string()};

Обратите внимание, что при передаче значения перечисления в функцию действуют те же самые правила передачи владения. Поэтому в примере выше, чтобы передачи владения не произошло, применяется передача по ссылке.

Помощь сайту
Юмани:
410011174743222
Номер карты:
4048415020898850