Разные подходы для решения одной задачи#
Введение:#
В программировании приняты несколько парадигм. Cегодня остановлюсь и рассмотрю императивный и функциональные стили.
Давайте напишем код который выполняет одинаковую задачу, но использует при этом различные подходы. Но до этого краткая справка по стилям.
Императивное программирование связано с идеей когда мы описываем операции (инструкции) как действия в обычной жизни. Последовательность неких действий, манипуляций. Есть некое состояние приложения и последовательность операций изменяет это состояние.
Функциональное программирование плотно интегрировано в современные языки: будь то js, ruby, java, dart и др. Map, reduce, filter наверняка уже где-то встречались 😉
Функциональный подход, это когда функция возвращает другую функцию. Вот такое краткое определение 😆 которое конечно не отражает всего многообразия этого царства. Но я не хочу тратить ваше время, а поэтому поехали писать код)
Приложение:#
Давайте представим что нам нужно написать приложение для умного дома которое фильтрует и обрабатывает данные от сенсоров.
Определим структуру для данных от датчиков#
Пусть это будет температурный датчик DS18B20 с тремя ногами и работющий по протоколу 1-wire. Это не так важно для нашего примера, но зато позволяет проникнуть в мир умного дома и немного оживляет повествование 😁
#[derive(Debug)]
struct Sensor {
id: String,
temperature: f32,
}Определили структуру для сенсора, переходим к основному коду.
Примечание: derive(Debug) trait помогает при отладке кода и позволяет вывести информацию об объекте передав {:?} или {:#?} при форматировании строки. Пример -> println!("New sensor found: {:?}", Sensor { id: "123".to_string(), temperature: 20.0 }); подробнее в доке
Реализация в разных стилях#
Давайте посмотрим на оба подхода в действии. Ниже представлены интерактивные слайды, где на первом шаге показан императивный стиль, а на втором — функциональный.
Сравнение подходов:#
Императивный стиль:
- Особенности: большое количество строчек кода, ручной перебор элементов в цикле
for, ручная проверкаOptionиResult. - Минусы: код перегружен деталями управления памятью и состоянием, менее читаем, требует аллокации временных коллекций.
- Особенности: большое количество строчек кода, ручной перебор элементов в цикле
Функциональный стиль:
- Особенности: использование цепочки адаптеров итераторов (
map,flatten,filter). - Плюсы: высокая читаемость, отсутствие необходимости изменять состояние вручную, лаконичность.
- Особенности: использование цепочки адаптеров итераторов (
Iterator::collect#
Плюс использования Iterator::collect что нам не нужно аллоцировать лишнюю коллекцию и добавлять туда элементы в цикле. Метод collect позволяет взять итератор и конвертировать его в коллекцию для удобной дальнейшей работы или вывода.
Еще один небольшой пример:
let input = vec![
"Hello".to_string(),
"World!".to_string(),
"From".to_string(),
"E@Gle".to_string(),
"Blog".to_string(),
];
let output: Vec<String> = input.iter().cloned().collect();
println!("{:?}", output);Бонус#
Предлагаю пройтись по методам которые могут вызвать вопросы, а ведь они часто встречаются в исходниках программ написанных на rust
is_some#
Метод is_some вызывается для типа Option и возвращает true, если Option является Some, и false, если None.
to_owned#
Метод to_owned берет копию объекта и передаёт владение вызывающей стороне или как написано в доке преобразует заимствованные данные в собственные. Обычно он используется для создания String из &str.
unwrap#
Метод unwrap извлекает значение из Option, если оно является Some, иначе выбрасывает панику, если Option является None.
Считается, что лучше использовать его пореже поскольку с паникой завершается выполнение программы. Про обработку ошибок будет в другой статье.
flatten#
Метод flatten преобразует Option<Option
ok#
Метод ok преобразует Result в Option. Если результат Ok, то возвращается Some, в противном случае возвращается None.
parse::<F>()#
Механизм parse::
let four: u32 = "4".parse().unwrap();
assert_eq!(4, four);Заключение:#
Надеюсь, что заметка поможет еще лучше познакомиться с языком Rust и увидеть, что это современный гибкий язык не заточенный на какой-то один стиль написания кода.
Rust собирает в себе лучшее из мира программирования.
Если что-то осталось непонятным, пожалуйста изучите, что делает каждая строка и прочитайте комментарии к коду. И тогда, я верю, белых пятен станет намного меньше.
История обновлений
- Добавил подробное сравнение производительности и рекомендации по использованию метода
collect.
- Обновил примеры кода под стандарты новой редакции Rust.


