2

マクロを使用して、特定のタイプのすべてのサブクラスに一致する一致ステートメントを作成しようとしています。しかし、ケース クラスのフィールド値の抽出に問題があります。例えば:

sealed abstract class Foobar
case class Foo(x:Int,f:Foobar) extends Foobar
case class Bar(s:String, f:Foobar) extends Foobar

Foobar が指定された場合、次のようなコードを作成したいと思います。

 e1 match {
   case Foo(args) => args.toString
   case Bar(args) => args.toString
 }

それは私がこれまでに得たものです:

  def eqImpl[A: c.WeakTypeTag](c: Context)(e1: c.Expr[A], e2: c.Expr[A]): c.Expr[Boolean] = {
    import c.universe._

    val tpe = c.weakTypeOf[A].typeSymbol.asClass
    tpe.typeSignature // SI-7046
    val subclasses = tpe.knownDirectSubclasses

    val cases = 
      subclasses.map{ clazz =>
      cq"x: $clazz => x " 
    }
    println(cases)
    reify(true)
  }

このコードは Foo と Bar に一致しますが、右側に必要なフィールドを抽出できません。

4

1 に答える 1

1

だから私はそれがほとんどうまくいった、ここに例があります:

def eqImpl[A: c.WeakTypeTag](c: Context)(e1: c.Expr[A], e2: c.Expr[A]): c.Expr[Boolean] = {
    import c.universe._
    val tpe = c.weakTypeOf[A].typeSymbol.asClass
    tpe.typeSignature // SI-7046 workaround 

    val subclasses = tpe.knownDirectSubclasses

    val cases = 
      subclasses.map{ case clazz : ClassSymbol =>
        require (clazz.isCaseClass)
        val name = clazz.companionSymbol.name
        val fields = clazz.typeSignature.declarations.collect {
        case m: MethodSymbol if m.isCaseAccessor => m.name}
        //pattern for the fields of the left and right side side
        val lFields = fields.map{ m => pq"""${m+"L":TermName}"""} 
        val rFields = fields.map{ m => pq"""${m+"R":TermName}"""} side
        //right hand side of the case statment 
        val eqFields = 
          fields.map{ m => q"""${m+"R":TermName} == ${m+"L":TermName}"""}.reduce[Tree]{ 
            case (acc,n) => q"$acc && $n"}

        cq"($name(..$lFields),$name(..$rFields)) => $eqFields  " 
    }
    val matchStmt = q"""Tuple2[$tpe,$tpe]($e1,$e2) match {
          case ..$cases
          case _ => false }"""
    c.Expr[Boolean](matchStmt)
  }
}

このコードは、タプルに一致する match ステートメントを作成します。タプルの両側が同じケース クラスのインスタンスである場合、フィールドが比較されます。すべてのフィールドが等しい場合、True が返されます。これは特に現実的な例ではないことは承知していますが、参考になれば幸いです。質問の例では、これにより次が生成されます。

Tuple2[Foobar,Foobar](e1,e2) match {
     case (Foo(xL,fL),Foo(xR,fR) => xL == xR && fL == fR
     case (Bar(sL,fL),Bar(sR,fR) => sL == sR && fL == fR
     case _                      => false
 }
于 2013-10-10T11:35:27.190 に答える