引号与拼接
将代码视为数据
引号与拼接 是 CoddyKit 上的免费 Scala for Backend Engineering & Functional Programming 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Scala for Backend Engineering & Functional Programming 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Scala for Backend Engineering & Functional Programming 课程共包含 4 节课。
代码即数据
Scala 3 元编程将代码视为数据。引用会将一段代码捕获为 Expr,而拼接会将 Expr 插回代码中。
引用:'{ ... }
'{ expr } 会将一个表达式转换为 Expr[T]。代码不会被执行,而是会变成宏可以操作的值。
import scala.quoted.*
def greeting(using Quotes): Expr[String] = '{ "Hello, " + "world" }拼接:${ ... }
${ expr } 会将 Expr 插入外层引用中,把生成的代码片段拼接起来。引用和拼接互为逆操作。
import scala.quoted.*
def doubled(x: Expr[Int])(using Quotes): Expr[Int] = '{ ${ x } * 2 }拼接已提升的值
在引用中,您可以拼接通过 Expr(...) 提升的值,将编译时常量嵌入生成的代码。
import scala.quoted.*
def addN(x: Expr[Int], n: Int)(using Quotes): Expr[Int] =
'{ ${ x } + ${ Expr(n) } }递归构建代码
宏可以在循环或递归中组合引用和拼接来构建复杂表达式,例如将幂运算展开为重复的乘法。
import scala.quoted.*
def pow(x: Expr[Double], n: Int)(using Quotes): Expr[Double] =
if (n == 0) '{ 1.0 } else '{ ${ x } * ${ pow(x, n - 1) } }对引用进行模式匹配
您可以通过匹配引用模式来解构代码。这会检查表达式的结构,以便对其进行优化或重写。
import scala.quoted.*
def optimize(e: Expr[Int])(using Quotes): Expr[Int] = e match {
case '{ ($a: Int) + 0 } => a
case _ => e
}Type[T] 与带引用的类型
正如 Expr[T] 携带一个表达式,Type[T] 携带一个类型。使用 '[T] 引用类型,并使用 given Type[T] 在需要类型的地方拼接它。
import scala.quoted.*
def typeName[T](using t: Type[T], q: Quotes): Expr[String] =
Expr(Type.show[T])反射 API
对于更底层的操作,quotes.reflect 会公开抽象语法树(Term、Symbol、TypeRepr),因此您可以检查或构建引用无法直接表达的代码。
import scala.quoted.*
def show(e: Expr[Any])(using q: Quotes): Expr[String] = {
import q.reflect.*
Expr(e.asTerm.show)
}在不同层级之间往返转换
使用 asTerm 将 Expr 转换为 Term,再使用 asExpr / asExprOf[T] 转换回来。这连接了高级引用 API 与反射 API。
import scala.quoted.*
def ident[T: Type](e: Expr[T])(using q: Quotes): Expr[T] = {
import q.reflect.*
e.asTerm.asExprOf[T]
}运行时对应实现
上面的递归幂运算宏会展开为普通乘法。这个自包含的运行时版本展示了生成代码将产生的相同结果。
object Main {
def pow(x: Double, n: Int): Double =
if (n == 0) 1.0 else x * pow(x, n - 1)
def main(args: Array[String]): Unit = {
println(pow(3.0, 2)) // 9.0
}
}引用和拼接互为逆操作
请记住二者的对应关系:'{ } 将代码提升为 Expr;${ } 将 Expr 放回代码中。正确嵌套它们是构建宏的核心。
快速检查
拼接运算符 ${ x } 在引用中有什么作用?
回顾
您学习了引用和拼接:
'{ }将代码引用为Expr[T]${ }将Expr拼接到代码中- 使用引用模式匹配来解构代码
Type[T]和reflectAPI
下一节:实用宏。
常见问题解答
「引号与拼接」课时是免费的吗?
是的 — 「引号与拼接」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Scala for Backend Engineering & Functional Programming 课程的其余内容,请升级到 CoddyKit PRO。 Scala for Backend Engineering & Functional Programming 课程共包含 4 节课。
「引号与拼接」这节课中我会学到什么?
将代码视为数据 你通过在浏览器中直接运行的动手代码来练习 Scala for Backend Engineering & Functional Programming,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Scala for Backend Engineering & Functional Programming 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Scala for Backend Engineering & Functional Programming 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「引号与拼接」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Scala for Backend Engineering & Functional Programming 课中编写并运行代码吗?
能。每节 Scala for Backend Engineering & Functional Programming 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。