Комментарии 11
Статья не очень по одной простой причине - не объясняется нормально синтаксис макросов. Нет примеров использования по каждому макросу в материале. Без всего этого статья для незнающего человека бесполезна. Вам может казаться что все просто и понятно, но для человека кто видит синтаксис впервые , увы, нет
Такое чувство что языки Rust и С++ соревнуются, у кого более непонятное и запутанное метапрограммирование. Между тем, синтаксические макросы сами по себе - простая концепция, и при правильной реализации достаточно одной единственной разновидности, а не четырех.
Не, зря ты так. Понятно, что если на Rust ты не пишешь, то понимать это все достаточно трудно, но если языком пользуешься, то у Rust код макросов достаточно хорошо читается и поддерживается.
Какие-то простые вещи, возможно, с первого взгляда будут казаться и сложнее, чем в плюсах, однако чем сложнее логика макроса, тем сильнее начинает выигрывать Rust и выигрывать ощутимо.
Но я все-таки не говорю, что макросы в Rust идеальны. Конечно, можно бы и еще получше :)
Увы, но не так-то просто эту самую единственную разновидность синтаксических макросов подружить с подсветкой синтаксиса в IDE и контекстными подсказками в ней же.
Макросы — это чистые функции, исполняемые во время компиляции. Достаточно иметь в языке функции, чистота которых гарантирована, и это известно во время компиляции. Тогда такие функции, имея константные аргументы, могут быть выполнены во время компиляции. И тогда макросам вообще не нужен специальный синтаксис.
Чистые функции это самая очевидная, но не единственно возможная реализация. Нет ничего плохого в том, чтобы создавать во время компиляции объекты, сохраняющие состояние между вызовами макросов и т.п. (и даже взаимодействовать с внешним миром - к примеру читать и писать в файлы и базы данных). Другое дело что такой код сложнее отлаживать, и ошибки в нем могут привести к некорректной работе компилятора.
А макросы в Си - это вообще подстановка без выполнения кода при компиляции (т.е. чистая квазицитата). И как показывает практика, во многих случаях такие макросы более чем достаточны (другое дело что в Си они реализованы на лексическом, а не на синтаксическом уровне, отсюда они игнорируют структуру кода, области видимости, права доступа и т.п.). В Rust этому вроде как соответствуют декларативные макросы (и они таки синтаксические), но какой же кривой и мозгодробительный синтаксис!
В rust макросы могут быть не чистыми, и это активно используется. Например, крейт sqlx, имея подключение к базе данных, может проверять валидность sql запросов во время компиляции.
Ну и как вы без специального синтаксиса сделаете макрос, добавляющий ну вот хотя бы возможность сериализации структуры? Вот чтобы в цикле пройтись по всем полям и сериализовать их, учитывая их тип данных?
Или вот взять макрос intrusive_adapter из крейта intrusive_collections, добавляющий новую структуру с особой небезопасной реализацией конкретного трейта. Как его делать просто на чистых функциях?
Интересно, почему vec! не делает reserve. Размер ведь известен во время компиляции
Потому что это просто пример того, как это можно реализовать, написанный автором статьи. В самом Rust он реализован по-другому. Если в двух словах: в случае перечисления элементов, вектор создаётся из boxed slice - то есть, как раз за одну аллокацию нужного размера.
Делаем макросы в Rust