我正在玩 Scala 新宏并发现了这个gist from akshaal。看起来我不太明白。
鉴于以下特征(fieldsMacro 或多或少与 akshaal 示例中的相同)
case class Field[I <: AnyRef](name: String, get: I => Any)
type Fields[I <: AnyRef] = List[Field[I]]
trait FieldAccess {
import FieldMacors._
import Field._
import language.experimental.macros
def fields[T <: AnyRef]: Fields[T] = macro fieldsMacro[T]
def field[T <: AnyRef](name: String): Fields[T] = fields[T].headOption <-- does not work!
^
}
object FieldMacors {
import language.experimental.macros
import Field._
def fields[T <: AnyRef]: Fields[T] = macro fieldsMacro[T]
/**
* Get a list of fiels
*/
def fieldsMacro[T <: AnyRef: c.TypeTag](c: Context): c.Expr[Fields[T]] = {
import c.universe._
val instanceT = c.typeOf[T]
val fields = instanceT.members.filter(member => member.isTerm && !member.isMethod)
// transform an iterable of expr in a expr of list.
def foldIntoListExpr[T: c.TypeTag](exprs: Iterable[c.Expr[T]]): c.Expr[List[T]] =
exprs.foldLeft(reify { Nil: List[T] }) {
(accumExpr, expr) =>
reify { expr.splice :: accumExpr.splice }
}
val fieldAccessores = for (field <- fields) yield {
val name = field.name.toString.trim // Why is there a space at the end of field name?!
val nameExpr = c literal name
// Construct expression (x : $I) => x.$name
val getFunArgTree = ValDef(Modifiers(), newTermName("x"), TypeTree(instanceT), EmptyTree)
val getFunBodyTree = Select(Ident(newTermName("x")), newTermName(name))
val getFunExpr = c.Expr[T => Any](Function(List(getFunArgTree), getFunBodyTree))
reify {
Field[T](name = nameExpr.splice, get = getFunExpr.splice)
}
}
foldIntoListExpr(fieldAccessores)
}
}
编译器抱怨
“无法从具有未解析类型参数的类型 T 创建 TypeTag”
我如何设法让 T 进入宏或者我必须实现另一个使用 fieldsMacro 的宏
T: TypeTag
类型参数的上下文绑定T
意味着您需要提供具体的类型参数来代替此参数(即不包含对未标记类型参数或抽象类型成员的引用)。否则会发生错误。
例子:
scala> val ru = scala.reflect.runtime.universe
ru @ 6d657803: scala.reflect.api.JavaUniverse = scala.reflect.runtime.JavaUniverse@6d657803
scala> def foo[T: ru.TypeTag] = implicitly[ru.TypeTag[T]]
foo: [T](implicit evidence$1: reflect.runtime.universe.TypeTag[T])reflect.runtime.universe.TypeTag[T]
scala> foo[Int]
res0 @ 7eeb8007: reflect.runtime.universe.TypeTag[Int] = TypeTag[Int]
scala> foo[List[Int]]
res1 @ 7d53ccbe: reflect.runtime.universe.TypeTag[List[Int]] = TypeTag[scala.List[Int]]
scala> def bar[T] = foo[T] // T is not a concrete type here, hence the error
<console>:26: error: No TypeTag available for T
def bar[T] = foo[T]
^
scala> def bar[T] = foo[List[T]] // T being not concrete renders
// the entire compound type not concrete
<console>:26: error: No TypeTag available for List[T]
def bar[T] = foo[List[T]]
^
scala> def bar[T: TypeTag] = foo[T] // to the contrast T is concrete here
// because it's bound by a concrete tag bound
bar: [T](implicit evidence$1: reflect.runtime.universe.TypeTag[T])reflect.runtime.universe.TypeTag[T]
scala> bar[Int]
res2 @ 7eeb8007: reflect.runtime.universe.TypeTag[Int] = TypeTag[Int]
scala> def bar[T: TypeTag] = foo[List[T]]
bar: [T](implicit evidence$1: reflect.runtime.universe.TypeTag[T])reflect.runtime.universe.TypeTag[List[T]]
scala> bar[Int]
res3 @ 1a108c98: reflect.runtime.universe.TypeTag[List[Int]] = TypeTag[scala.List[Int]]
scala> bar[List[Int]]
res4 @ 76d5989c: reflect.runtime.universe.TypeTag[List[List[Int]]] = TypeTag[scala.List[scala.List[Int]]]
拥有在编译时强制执行的具体类型的概念是很有用的。默认情况下启用具体类型标签很有用,并且在https://issues.scala-lang.org/browse/SI-5884.
然而,正如您所看到的,宏中的具体类型标记可能会造成混乱,因为通常宏应该适用于具体类型和非具体类型。因此人们应该始终使用c.AbsTypeTag
反而。由于这个原因,我们不再允许c.TypeTag
2.10.0-M7 中的上下文边界:https://github.com/scala/scala/commit/788478d3ab.
Edit。在2.10.0-RC1中一些AbsTypeTag
已更名为WeakTypeTag
。有关类型标签的其他所有内容都保持不变。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)