Макросы в Rust. macro_rules

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

Я долго откладывал этот день, но вечно откладывать было нельзя. Что ж, время пришло. Пора наконец разобраться с макросами в Rust. Ну или хотя бы начать.

Давайте сразу определимся, зачем вы хотите их использовать. Макросы - это про метапрограммирование и, можно даже сказать отчасти про reflective программирование. Я, конечно, не разработчик паттернов и стандартов, но использовать макрос (объявленный macro_rules!) как замену функции, как по мне, плохая идея. Во-первых, потому, что функция принимает переменные конкретного типа, а макрос, который принимает переменную, банально не знает её типа, соответственно, понять смысл операций можно только по названию и по самой сигнатуре макроса. А синтаксис макросов не то чтобы очень очевиден…

Но, надеюсь, благодаря этой статье он станет более понятен для вас.

Что за зверь такой, macro_rules!?

Давайте начнём с самого простого. macro_rules! - наш путь к написанию макросов, встроенный прямо в стандартную библиотеку. Давайте начнём с простого примера - макрос, который делает то же, что и unwrap. Это, конечно, невероятно глупая и плохая идея, но для примера подойдёт.

Обратите внимание, что макрос объявлен до вызова.

Проверить: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=53294a2c156ae7430bad305af7c1da17

macro_rules! uncover{

    ($var:ident) => {

        match $var{

            Some(t) => t,

            None => panic!("None value")

        }

    }

}

fn main(){

    let x = Some(2i32);

    let unwrapped = uncover!(x);

    println!("{}", unwrapped);

}

Ну-с… давайте разбираться. Что же мы сделали? Перво-наперво, мы объявили макрос uncover: 

macro_rules! uncover

Который принимает переменную $var типа ident. Вообще говоря, ident это не только переменная, но и название функции. Полный список типов, которые можно передать как аргумент в макрос можно поглядеть тут: https://doc.rust-lang.org/rust-by-example/macros/designators.html

В каком-то смысле, вы передаёте в макрос не переменную, а код. Все, что знает макрос про $var - это название того, что мы передали в uncover (в нашем случае, х).

Далее идёт код, который вполне себе похож на нативный Rust код, однако есть момент, который бросается в глаза: мы используем переменную со знаком доллара. Итак, что же сделает этот макрос при вызове? Он вставит всю сигнатуру на то место, где вы его вызываете. То есть по сути в рантайме код будет выглядеть не так:

let unwrapped = uncover!(x);

А так:

let unwrapped = match x{

    Some(t) => t,

    None => panic!(“None value”)

};

Использовать макросы как обычные функции - плохая идея. Они делают не то же самое, что функции (хотя чем-то похоже на inline-фуннции). И хоть код 

let x = 2i32;

let unwrapped = uncover!(x);

не скомпилируется, лучше использовать старые-добрые функции. Всё-таки, они более явные и отлично выполняют цель, с которой были созданы.

Summary

Итак, зачем же тебе, простой Иван город Тверь, писать макросы? Да не знаю, сам подумай. Может, есть повторяющееся место в коде, под которое идеально подойдёт макрос? Или ты написал нереальную реализацию списка со скоростью работы O(1) и хочешь инициализировать его вот так: list![1,2,3] ? Ну или тебе просто нравится заниматься метапрограммированием? Правда, последнее трудно вяжется с macro_rules! Всё-таки, в языке есть более мощное метапрограммирование, тёмная магия proc_macro, syn, qoute и TokenTree, но о ней как-нибудь в другой раз.

Вот, собственно, и всё. Писать макросы с помощью macro_rules не так-то сложно, главное разобраться в базовых правилах. Может, это сбережёт ваши нервы и/или деньги. Конечно, я не затрагивал в этой статье самое интересное, это наиболее простое из того, что есть. Цель статьи - показать, что макросы - это несложно.

Пишите, если хотите статью про proc_macro и syn, там действительно есть на что посмотреть.

Источник: https://habr.com/ru/post/550460/


Интересные статьи

Интересные статьи

В данной пошаговой инструкции мы подробно опишем весь процесс получения доступа к WhatsApp Business API через официального партнера Facebook — сервис Gupshup и подключени...
Ваш сайт работает на 1С-Битрикс? Каждому клиенту вы даёте собственную скидку или назначаете персональную цену на товар? Со временем в вашей 1С сложилась непростая логика ценообразования и формирования...
Бизнес-смыслы появились в Битриксе в начале 2016 года, но мало кто понимает, как их правильно использовать для удобной настройки интернет-магазинов.
В этой статье разберёмся, как реализовать поддержку страничной памяти в нашем ядре. Сначала изучим различные методы, чтобы фреймы физической таблицы страниц стали доступны ядру, и обсудим их преи...
Согласно многочисленным исследованиям поведения пользователей на сайте, порядка 25% посетителей покидают ресурс, если страница грузится более 4 секунд.