检查抽象类型时奇怪的 Scala 宏行为?
Strange scala macro behaviour when checking for abstract type?
我想在 scala 中编写一个简单的 type builder。不管怎样,它自己的类型构建器就像一个魅力。
我想在打字机中检查 abstract class.
在运行时没有问题:
if (classSymbol.isAbstract) throw new IllegalArgumentException("Provided class is abstract")
我用 TypeTag 属性标记方法,因此 scala 不会在编译期间擦除时间。
def createInstance[T: TypeTag]: T
无论如何,这是可行的。我不喜欢这种方式,因为用户可以输入一个 摘要 class 并想要创建它。我不想在运行时检查参数异常。
所以我认为在编译时间期间检查正确的类型真的很酷。
这是宏函数的完整代码:
object ClassCheckMacro {
def checkClass[T](x: T): T = macro checkClassImpl[T]
def checkClassImpl[T: c.WeakTypeTag](c: blackbox.Context)(x: c.Tree) = {
import c.universe._
val symbol = weakTypeOf[T].typeSymbol
if (symbol.isAbstract) {
c.abort(c.enclosingPosition, s"${symbol.fullName} must be a class")
} else {
c.Expr(q"($x)")
}
}
}
每次我使用这个宏时,我都会收到中止消息 "must be a class"。
它是 class 还是抽象类型并不重要。
用法:
val typeInfo = typeOf[T]
val classSymbol = typeInfo.typeSymbol.asClass
ClassCheckMacro.checkClass(classSymbol)
对于这种 "strange" 行为有任何提示吗?
x
只是一个值。
$ scalam -language:_
Welcome to Scala 2.12.0-M5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_92).
Type in expressions for evaluation. Or try :help.
scala> import reflect.macros._
import reflect.macros._
scala> def checkClassImpl[T: c.WeakTypeTag](c: blackbox.Context)(x: c.Tree) = {
| import c.universe._
| val symbol = weakTypeOf[T].typeSymbol
| if (symbol.isAbstract) {
| c.abort(c.enclosingPosition, s"${symbol.fullName} must be a class")
| } else {
| c.Expr(q"($x)")
| }
| }
checkClassImpl: [T](c: scala.reflect.macros.blackbox.Context)(x: c.Tree)(implicit evidence: c.WeakTypeTag[T])c.Expr[T]
scala> def checkClass[T](x: T): T = macro checkClassImpl[T]
defined term macro checkClass: [T](x: T)T
scala> class C
defined class C
scala> checkClass[C](null)
res0: C = null
scala> abstract class K
defined class K
scala> checkClass[K](null)
<console>:17: error: K must be a class
checkClass[K](null)
^
正在将工作笔记本电脑升级到 Windows 10...
我想在 scala 中编写一个简单的 type builder。不管怎样,它自己的类型构建器就像一个魅力。 我想在打字机中检查 abstract class.
在运行时没有问题:
if (classSymbol.isAbstract) throw new IllegalArgumentException("Provided class is abstract")
我用 TypeTag 属性标记方法,因此 scala 不会在编译期间擦除时间。
def createInstance[T: TypeTag]: T
无论如何,这是可行的。我不喜欢这种方式,因为用户可以输入一个 摘要 class 并想要创建它。我不想在运行时检查参数异常。
所以我认为在编译时间期间检查正确的类型真的很酷。 这是宏函数的完整代码:
object ClassCheckMacro {
def checkClass[T](x: T): T = macro checkClassImpl[T]
def checkClassImpl[T: c.WeakTypeTag](c: blackbox.Context)(x: c.Tree) = {
import c.universe._
val symbol = weakTypeOf[T].typeSymbol
if (symbol.isAbstract) {
c.abort(c.enclosingPosition, s"${symbol.fullName} must be a class")
} else {
c.Expr(q"($x)")
}
}
}
每次我使用这个宏时,我都会收到中止消息 "must be a class"。 它是 class 还是抽象类型并不重要。 用法:
val typeInfo = typeOf[T]
val classSymbol = typeInfo.typeSymbol.asClass
ClassCheckMacro.checkClass(classSymbol)
对于这种 "strange" 行为有任何提示吗?
x
只是一个值。
$ scalam -language:_
Welcome to Scala 2.12.0-M5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_92).
Type in expressions for evaluation. Or try :help.
scala> import reflect.macros._
import reflect.macros._
scala> def checkClassImpl[T: c.WeakTypeTag](c: blackbox.Context)(x: c.Tree) = {
| import c.universe._
| val symbol = weakTypeOf[T].typeSymbol
| if (symbol.isAbstract) {
| c.abort(c.enclosingPosition, s"${symbol.fullName} must be a class")
| } else {
| c.Expr(q"($x)")
| }
| }
checkClassImpl: [T](c: scala.reflect.macros.blackbox.Context)(x: c.Tree)(implicit evidence: c.WeakTypeTag[T])c.Expr[T]
scala> def checkClass[T](x: T): T = macro checkClassImpl[T]
defined term macro checkClass: [T](x: T)T
scala> class C
defined class C
scala> checkClass[C](null)
res0: C = null
scala> abstract class K
defined class K
scala> checkClass[K](null)
<console>:17: error: K must be a class
checkClass[K](null)
^
正在将工作笔记本电脑升级到 Windows 10...