9

私は Scalas の新しいマクロをいじっていて、 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 を使用する別のマクロを実装する必要があります

4

1 に答える 1

13

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

編集します。2.10.0-RC1 では、一部のAbsTypeTag名前が に変更されましたWeakTypeTag。タイプタグに関する他のすべては同じままです。

于 2012-08-23T16:23:30.027 に答える