Основы макросов
Код на этапе компиляции
«Основы макросов» — бесплатный урок Scala for Backend Engineering & Functional Programming на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Scala for Backend Engineering & Functional Programming, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Scala for Backend Engineering & Functional Programming содержит 4 уроков всего.
Что такое макрос?
Макрос — это код, который выполняется во время компиляции для генерации другого кода. Макросы Scala 3 позволяют анализировать аргументы, создавать выражения и вставлять их в программу до её компиляции.
Шаблон Inline + Macro
Макрос вызывается из inline def, который делегирует выполнение методу, отмеченному с помощью ${ ... }. Inline-определение является общедоступным API, а реализация макроса выполняется в компиляторе.
import scala.quoted.*
inline def power(x: Double, inline n: Int): Double =
${ powerImpl('x, 'n) }Контекст Quotes
Каждая реализация макроса принимает неявный контекст Quotes. Он предоставляет доступ к API отражения, а также возможность создавать выражения и вставлять их в код.
import scala.quoted.*
def powerImpl(x: Expr[Double], n: Expr[Int])(using Quotes): Expr[Double] =
???Expr[T]
Expr[T] представляет типизированное выражение типа T как данные времени компиляции. Макросы получают и возвращают значения Expr.
Подъём значений в Expr
Expr(value) поднимает вычисленное макросом значение времени выполнения в выражение, чтобы затем вставить его обратно. Это работает для любого типа, у которого есть экземпляр ToExpr.
import scala.quoted.*
def constImpl(using Quotes): Expr[Int] = Expr(42)Извлечение константных аргументов
n.value (или n.valueOrAbort) извлекает константу из Expr, если аргумент известен статически, чтобы макрос мог использовать её в ветвлении.
import scala.quoted.*
def powerImpl(x: Expr[Double], n: Expr[Int])(using Quotes): Expr[Double] = {
val exp = n.valueOrAbort
??? // build x*x*...*x exp times
}Сообщение об ошибках
Используйте quotes.reflect.report.errorAndAbort, чтобы выдать ошибку компиляции с сообщением и указанием местоположения, если предварительные условия макроса не выполнены.
import scala.quoted.*
def check(n: Expr[Int])(using q: Quotes): Expr[Int] = {
import q.reflect.*
val v = n.valueOrAbort
if (v < 0) report.errorAndAbort("must be >= 0")
Expr(v)
}Где находятся макросы
Реализации макросов должны быть скомпилированы до кода, который их использует, — обычно в отдельном файле или модуле. Компилятор выполняет их во время компиляции вызывающего кода.
Распространённые случаи использования
Макросы используются для:
- выведения экземпляров typeclass (кодеки JSON и т. д.)
- проверки во время компиляции (регулярные выражения, SQL)
- ведения журнала с фиксацией позиций в исходном коде
- абстракций без затрат во время выполнения
Безопасность и гигиена
Макросы Scala 3 являются гигиеничными: сгенерированные идентификаторы не могут случайно захватить пользовательские переменные, а система типов проверяет сгенерированный код, предотвращая многие классические ошибки макросов.
Эквивалент во время выполнения
Макрос, вычисляющий степень во время компиляции, даёт тот же результат, что и эта самодостаточная версия, выполняемая во время работы программы, — но компилятор заранее встраивает умножения.
object Main {
def power(x: Double, n: Int): Double =
if (n == 0) 1.0 else x * power(x, n - 1)
def main(args: Array[String]): Unit = {
println(power(2.0, 3)) // 8.0
}
}Быстрая проверка
Какой тип представляет типизированное выражение времени компиляции, которое получают и возвращают макросы?
Итоги
Вы изучили основы макросов:
- макросы выполняются во время компиляции с помощью шаблона
inline def ... ${ } - контекст
QuotesиExpr[T] - подъём с помощью
Expr(...)и извлечение с помощью.value - сообщение об ошибках и гигиена
Далее: quotes и вставки.
Часто задаваемые вопросы
Урок «Основы макросов» бесплатный?
Да — полный текст урока «Основы макросов» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Scala for Backend Engineering & Functional Programming, подпишись на CoddyKit PRO. Курс Scala for Backend Engineering & Functional Programming содержит 4 уроков всего.
Чему я научусь в уроке «Основы макросов»?
Код на этапе компиляции Ты практикуешь Scala for Backend Engineering & Functional Programming с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Scala for Backend Engineering & Functional Programming?
Предыдущий опыт не требуется. Scala for Backend Engineering & Functional Programming на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Основы макросов»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Scala for Backend Engineering & Functional Programming?
Да. Каждый урок Scala for Backend Engineering & Functional Programming включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Встраиваемые методы
- Основы макросов
- Цитаты и вставки
- Практические макросы