マクロの基礎
コンパイル時のコードです。
「マクロの基礎」はCoddyKit上の無料Scala for Backend Engineering & Functional Programmingレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはScala for Backend Engineering & Functional Programming学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Scala for Backend Engineering & Functional Programmingコースには全4レッスンが含まれています。
マクロとは
マクロとは、コンパイル時に実行され、別のコードを生成するコードです。Scala 3 のマクロでは、引数を調べたり、式を構築したりして、プログラムのコンパイル前にその式をプログラムへ出力できます。
Inline + Macro パターン
マクロは、${ ... } が付いたメソッドへ処理を委譲する inline def から呼び出します。inline def が公開 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)
}マクロの配置場所
マクロ実装は、それを使用するコードより前にコンパイルする必要があります。通常は別のファイルまたはモジュールに配置します。コンパイラーは呼び出し側のコンパイル中にマクロを実行します。
一般的なユースケース
マクロは次の用途で活用されます:
- 型クラスの導出(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による抽出- エラー報告と衛生性
次はクォートとスプライスです。
よくある質問
「マクロの基礎」レッスンは無料ですか?
はい。「マクロの基礎」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Scala for Backend Engineering & Functional Programmingコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Scala for Backend Engineering & Functional Programmingコースには全4レッスンが含まれています。
「マクロの基礎」で何を学びますか?
コンパイル時のコードです。 ブラウザで直接実行するハンズオンコードでScala for Backend Engineering & Functional Programmingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Scala for Backend Engineering & Functional Programmingを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのScala for Backend Engineering & Functional Programmingは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「マクロの基礎」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このScala for Backend Engineering & Functional Programmingレッスンでコードを書いて実行できますか?
はい。すべてのScala for Backend Engineering & Functional Programmingレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。