Scala 宏:“无法从具有未解析类型参数的类型 T 创建 TypeTag" [英] Scala Macros: "cannot create TypeTag from a type T having unresolved type parameters"

查看:15
本文介绍了Scala 宏:“无法从具有未解析类型参数的类型 T 创建 TypeTag"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 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"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆