Макрос — способ трансформации кода перед компиляцией. То же: macros.
Макросы можно вовсе не применять, но иногда это удобно. У меня, например, вошло в привычку использовать встроенный макрос ?MODULE при открытии таблиц ETS/DETS. Этот встроенный макрос препроцессором epp заменяется на атом названия модуля. Эта привычка обеспечивает то, что у таблиц будет оригинальное название.
Всего, кстати, встроенных макросов три:
?FILE заменяется на название текущего файла.?MODULE заменяется на название модуля.?LINE заменяется на номер текущей строки.Сначала epp производит некоторые манипуляции с файлом кода, а потом этот обновлённый файл поступает уже компилятору. Если мы желаем увидеть результат работы epp, можно запустить erlc с ключом -P.
Создадим пробный файл с названием proba.erl.
-module(proba).
main() ->
?FILE,
?MODULE,
?LINE.
В нём три макроса (встроенные). Исполнив команду erlc -P proba.erl, мы получим файл proba.P.
-file("proba.erl", 1).
-module(proba).
main() ->
"proba.erl",
proba,
6.
Как видим, вместо одного макроса был вставлена строка с названием файла, вместо другого — атом названия модуля, вместо третьего — номер текущей строки.
Макросы могут как повышать, так и понижать читабельность кода. Это похоже на человеческую речь: если мы пользуемся специальной терминологией, то до какого-то предела это нормально, но если будем сыпать терминами, в которых и сами-то не очень разбираемся, речь наша будет неразборчивой. Надёжным будет всегда пользоваться привычными макросами, которые от модуля к модулю делают одно и то же.
Макросы бывают двух видов: простые и сложные. В простых макросах какая-то константа заменится на что-либо другое.
-module(proba).
-define(MYNAME, "Алексей Карманов").
main() ->
?MYNAME.
Для определения своего макроса (простого) используется форма -define(Константа, Замена).. epp заменит этот наш пример на следующее:
-file("proba.erl", 1).
-module(proba).
main() ->
"Алексей Карманов".
epp не занимается вычислениями. Он просто находит в определении макроса какой-то кусок кода и меняет константу на этот кусок кода.
-module(proba).
-define(TIME, time()).
main() ->
?TIME.
превратится в…
-file("proba.erl", 1).
-module(proba).
main() ->
time().
“Замена” может состоять из нескольких выражений, разделённых запятыми.
-module(proba).
-define(MATH, A = 5, B = 2, math:pow(5,2)).
main() ->
?MATH.
превратится в…
-file("proba.erl", 1).
-module(proba).
main() ->
A = 5,
B = 2,
math:pow(5, 2).
Второй вариант макросов — более сложный, он обладает функциональным характером. Если простые макросы заменяются всегда на что-то одно, то сложные имеют аргументы, и результат замены зависит от этих аргументов (они вставляются в него).
Предположим, нам надоело раз за разом писать io:format(..., чтобы выводить сообщения. Мы можем использовать макрос с каким-нибудь коротким названием (например, P).
-module(proba).
-define(P(X), io:format(X)).
main() ->
?P("Привет, мир!"),
?P("Какая чудесная погода!").
заменится на
-file("proba.erl", 1).
-module(proba).
main() ->
io:format("Привет, мир!"),
io:format("Какая чудесная погода!").
Атомы могут подставляться, например, в качестве названия модулей. Аргумент, конечно, можно использовать несколько раз. Может быть несколько аргументов.
-module(proba).
-define(R(X,Y), X:Y(X)).
main() ->
?R(compile,file).
заменится на
-file("proba.erl", 1).
-module(proba).
main() ->
compile:file(compile).
Не возбраняется называть макросы строчными буквами. Например, ?myname, а не ?MYNAME. Но мне больше нравится вариант с заглавными буквами. Это лишний раз напоминает, что макросы надо использовать осторожно.
Copyright © 2024 Алексей Карманов