此文档页面特定于 Scala 3,可能涵盖 Scala 2 中不可用的新概念。 除非另有说明,否则此页面中的所有代码示例都假设您使用的是 Scala 3。
内联
在内联以提高性能时要小心
为了最大程度地利用 JVM JIT 优化,您需要避免生成大型方法。
宏
即将推出
引用代码
保持引用可读
- 尽量避免使用
${...}
,其中包含任意表达式- 使用
$someExpr
- 使用
${ someExprFrom('localExpr) }
- 使用
为了说明,请考虑以下示例
val sc: StringContext = ...
'{ StringContext(${Varargs(sc.parts.map(Expr(_)))}: _*) }
相反,我们可以编写以下内容
val sc: StringContext = ...
val partExprs = sc.parts.map(Expr(_))
val partsExpr = Varargs(partExprs)
'{ StringContext($partsExpr: _*) }
在第二个示例中,引用的内容更加清晰。
避免嵌套上下文
请考虑以下代码
val y: Expr[Int] = ...
def body(x: Expr[Int])(using quotes.Nested) = '{ $x + $y }
'{ (x: Int) => ${ body('x) } }
相反,使用正常的上下文并传递所有需要的表达式。这样做还有一个好处,就是允许函数不在本地定义。
def body(x: Expr[Int], y: Expr[Int])(using Quotes) =
'{ $x + $y }
val y: Expr[Int] = ...
'{ (x: Int) => ${ body('x, y) } }
引号反映
对于本节,请考虑以下设置
object Box:
sealed trait Base
case class Leaf(x: Int) extends Base
// Quotes in contextual scope
val boxTpe : TypeRepr = TypeRepr.of[Box.type]
val baseTpe: TypeRepr = TypeRepr.of[Box.Base]
val baseSym: Symbol = baseTpe.typeSymbol
val leafTpe: TypeRepr = TypeRepr.of[Box.Leaf]
val leafSym: Symbol = leafTpe.typeSymbol
避免使用 Symbol.tree
在对象 sym: Symbol
上,sym.tree
返回与符号关联的 Tree
。使用此方法时要小心,因为符号的树可能未定义。当与符号关联的代码在与访问不同的时间定义时,如果未使用 -Yretain-trees
编译选项,则符号的 tree
将不可用。源自 Java 代码的符号没有关联的 tree
。
从 Symbol
获取 TypeRepr
在前面的标题中,我们看到应该避免使用 Symbol.tree
,因此您不应该在 sym: Symbol
上使用 sym.tree.tpe
。因此,要获取与 Symbol
对应的 TypeRepr
,建议在 tpe: TypeRepr
对象上使用 tpe.memberType
。
我们可以通过两种方式获得 Leaf
的 TypeRepr
TypeRepr.of[Box.Leaf]
boxTpe.memberType(leafSym)
(换句话说,我们请求Box
的成员的TypeRepr
,其符号等于leafSym
的符号。)
虽然这两种方法是等效的,但第一种方法只有在你已经知道你正在寻找类型 Box.Leaf
时才有可能。第二种方法允许你探索未知的 API。
使用 Symbol
来比较定义
了解更多关于 Symbols 的信息 这里.
Symbols 允许您使用 ==
来比较定义
leafSym == baseSym.children.head // Is true
但是,在 TypeRepr
上使用 ==
不会产生相同的结果
boxTpe.memberType(baseSym.children.head) == leafTpe // Is false
获取类型的 Symbol
有一个方便的快捷方式来获取 T
定义的 symbol。而不是
TypeTree.of[T].tpe.typeSymbol
您可以使用
TypeRepr.of[T].typeSymbol
使用模式匹配进入 API
模式匹配是 API 的一种非常符合人体工程学的方法。始终查看在 *Module
对象中定义的 unapply
方法。
在您的宏中搜索上下文范围
您可以使用 Implicits.search
搜索给定的实例。
例如
def summonOrFail[T: Type]: Expr[T] =
val tpe = TypeRepr.of[T]
Implicits.search(tpe) match
case success: ImplicitSearchSuccess =>
val implicitTerm = success.tree
implicitTerm.asExprOf[T]
case failure: ImplicitSearchFailure =>
reflect.report.throwError("Could not find an implicit for " + Type.show[T])
如果您正在编写宏,并且更喜欢处理 Expr
,Expr.summon
是 Implicits.search
的一个方便的包装器
def summonOrFail[T: Type]: Expr[T] =
Expr.summon[T] match
case Some(imp) => imp
case None => reflect.report.throwError("Could not find an implicit for " + Type.show[T])