问题描述
我正在使用Scalas新宏,并发现要点来自 akshaal .由于接缝,我不太明白.给定以下特征(fieldsMacro与akshaal示例中的字段基本相同)
I'm playing around with Scalas new macros and found this gist from akshaal. As it seams I did not quite get it.Given the following trait (the fieldsMacro is more or less the same as in akshaal example)
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"
the compiler complains about'Cannot create TypeTag from a type T having unresolved type parameters'
我如何设法将T传递给宏,或者必须实现另一个使用fieldsMacro的宏
How do I manage to get the T to the macro or must I implement another macro that uses the fieldsMacro
推荐答案
T: TypeTag
为类型参数绑定的上下文T
意味着您要求提供代替该参数的类型参数是具体的(即,不包含对未加标签的类型参数或抽象类型成员).否则会发生错误.
T: TypeTag
context bound for a type parameter T
means that you require type arguments provided in place of this parameter to be concrete (i.e. not contain references to untagged type parameters or abstract type members). Otherwise an error occurs.
示例:
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 .
Having a notion of concrete types to be enforcible at compile-time is useful. Having concrete type tags on by default is useful as well as described in https://issues.scala-lang.org/browse/SI-5884.
但是,正如您所看到的那样,宏中的具体类型标记可能会引起混乱,因为通常,宏应同时适用于具体类型和非具体类型.因此,应该始终使用c.AbsTypeTag
代替.由于这个原因,我们不再允许在2.10.0-M7中使用c.TypeTag
上下文范围: https://github.com/scala/scala/commit/788478d3ab .
However as you've seen yourself, concrete type tags in macros can be a source of confusion, because typically macros should work both for concrete and non-concrete types. Therefore one should always use c.AbsTypeTag
instead. Due to this reason we no longer allow c.TypeTag
context bounds in 2.10.0-M7: https://github.com/scala/scala/commit/788478d3ab.
修改.在2.10.0-RC1中,某些AbsTypeTag
已重命名为WeakTypeTag
.关于类型标签的其他所有内容都保持不变.
Edit. In 2.10.0-RC1 some AbsTypeTag
has been renamed to WeakTypeTag
. Everything else about type tags remains the same.
这篇关于Scala宏:“不能从具有未解析的类型参数的类型T创建TypeTag".的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!