Scala &引用;错误:缺少参数类型";在宏拼接过程中

Scala &引用;错误:缺少参数类型";在宏拼接过程中,scala,implicit,scala-macros,Scala,Implicit,Scala Macros,编辑:我发现了我的错误-我的递归案例的quasiquotes中有一个错误,导致它返回一个格式错误的序列 我正在尝试创建一个宏,该宏将案例类T转换为updateMap:Map[String,(play.api.libs.json.JsValue)=>Try[(T)=>T]](),其中Map的键是案例类的字段名,其思想是给定一个JsObject(“key”->JsValue)我们可以使用键从updateMap检索适当的更新方法,然后使用JsValue应用更新。我在非递归的情况下工作,也就是说,给定

编辑:我发现了我的错误-我的递归案例的quasiquotes中有一个错误,导致它返回一个格式错误的序列


我正在尝试创建一个宏,该宏将案例类
T
转换为
updateMap:Map[String,(play.api.libs.json.JsValue)=>Try[(T)=>T]]
(),其中Map的键是案例类的字段名,其思想是给定一个
JsObject(“key”->JsValue)
我们可以使用
键从
updateMap
检索适当的更新方法,然后使用
JsValue
应用更新。我在非递归的情况下工作,也就是说,给定一个case类,它没有任何其他case类作为字段。但是,我想扩展这个宏,以便它可以为包含其他case类的case类生成一个
updateMap

case class Inner(innerStr: String)
case class Outer(outerStr: String, inner: Inner)

updateMap[Outer] = {
  // updateMap[Inner]
  val innerMap = Map("innerStr" -> (str: String) => 
    Try { (i: Inner) => i.copy(innerStr = str) } )

  // updateMap[Outer]
  Map("outerStr" -> (str: String) => 
    Try { (o: Outer) => o.copy(outerStr = str) },
  "inner.innerStr" -> (str: String) => 
    Try { (o: Outer) => innerMap.get("innerStr").get(str).flatMap(lens => o.copy(inner = lens(o.inner))) })}
换句话说,给定
updateMap[Outer]
,我将能够直接更新对象的
outerStr
字段,或者我将能够更新对象的
inner.innerStr
字段,在这两种情况下都可以返回
Try[Outer]

对于非递归情况(
copyMapRec[internal]()
),代码可以正常工作,但是递归情况(
copyMapRec[Outer]()
)给了我一个“error:missing parameter type”错误-我假设我要么需要在某个地方提供一个隐式参数,要么我对拼接有一个基本的误解

下面的代码使用了一个
(String)=>Try[(T)=>T]
而不是
(JsValue)=>Try[(T)=>T]
,因此我不需要将播放框架导入REPL。我使用隐式转换将
JsValue
(或
String
)转换为适当的类型(这发生在基本大小写准引号中的
val x:$fieldType=str
行中;如果没有适当的隐式转换,则会出现编译器错误)


我修复了这个问题-最初在我的
递归方法中
Quasikotes使用了
innerMap.toSeq(…)
而不是
innerMap.toSeq.map(…)
-我忽略了先在REPL中测试代码,然后你应该粘贴编辑作为答案并关闭问题,因此问题显然得到了解决。
import scala.language.experimental.macros

def copyMapImplRec[T: c.WeakTypeTag](c: scala.reflect.macros.Context)(blacklist: c.Expr[String]*): c.Expr[Map[String, (String) => scala.util.Try[(T) => T]]] = {
  import c.universe._

  // Fields that should be omitted from the map
  val blacklistList: Seq[String] = blacklist.map(e => c.eval(c.Expr[String](c.resetAllAttrs(e.tree))))

  def rec(tpe: Type): c.Expr[Map[String, (String) => scala.util.Try[(T) => T]]] = {
    val typeName = tpe.typeSymbol.name.decoded

    // All fields in the case class's primary constructor, minus the blacklisted fields
    val fields = tpe.declarations.collectFirst {
      case m: MethodSymbol if m.isPrimaryConstructor => m
    }.get.paramss.head.filterNot(field => blacklistList.contains(typeName + "." + field.name.decoded))

    // Split the fields into case classes and non case classes
    val recursive = fields.filter(f => f.typeSignature.typeSymbol.isClass && f.typeSignature.typeSymbol.asClass.isCaseClass)
    val nonRecursive = fields.filterNot(f => f.typeSignature.typeSymbol.isClass && f.typeSignature.typeSymbol.asClass.isCaseClass)

    val recursiveMethods = recursive.map {
      field => {
        val fieldName = field.name
        val fieldNameDecoded = fieldName.decoded
        // Get the c.Expr[Map] for this case class
        val map = rec(field.typeSignature)
        // Construct an "inner.innerStr -> " seq of tuples from the "innerStr -> " seq of tuples
      q"""{
          val innerMap = $map
          innerMap.toSeq.map(tuple => ($fieldNameDecoded + "." + tuple._1) -> {
          (str: String) => {
            val innerUpdate = tuple._2(str)
            innerUpdate.map(innerUpdate => (outer: $tpe) => outer.copy($fieldName = innerUpdate(outer.$fieldName)))
          }
      })}"""
      }
    }

    val nonRecursiveMethods = nonRecursive.map {
      field => {
        val fieldName = field.name
        val fieldNameDecoded = fieldName.decoded
        val fieldType = field.typeSignature
        val fieldTypeName = fieldType.toString
        q"""{
          $fieldNameDecoded -> {
            (str: String) => scala.util.Try {
              val x: $fieldType = str
              (t: $tpe) => t.copy($fieldName = x)
            }.recoverWith {
              case e: Exception => scala.util.Failure(new IllegalArgumentException("Failed to parse " + str + " as " + $typeName + "." + $fieldNameDecoded + ": " + $fieldTypeName))
            }
         }}"""
      }
    }

    // Splice in all of the sequences of tuples, flatten the sequence, and construct a map
    c.Expr[Map[String, (String) => scala.util.Try[(T) => T]]] {
      q"""{ Map((List(..$recursiveMethods).flatten ++ List(..$nonRecursiveMethods)):_*) }"""
    }
  }

  rec(weakTypeOf[T])

}

def copyMapRec[T](blacklist: String*) = macro copyMapImplRec[T]