Преамбула: это основано на @Travis Brown's macro based solution для копирования свойств класса case.scala macros: defer тип вывода
Дано:
trait Entity[E <: Entity[E]]{self:E=>
def id: Int
def withId(id: Int) = MacroCopy.withId(self,id)
}
case class User(id: Int, name: String) extends Entity[User]
и Macro реализация:
object MacroCopy {
import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
def withId[T](entity: T, id: Int): T = macro withIdImpl[T]
def withIdImpl[T: c.WeakTypeTag]
(c: Context)(entity: c.Expr[T], id: c.Expr[Int]): c.Expr[T] = {
import c.universe._
val tree = reify(entity.splice).tree
val copy = entity.actualType.member(TermName("copy"))
val params = copy match {
case s: MethodSymbol if (s.paramLists.nonEmpty) => s.paramLists.head
case _ => c.abort(c.enclosingPosition, "No eligible copy method!")
}
c.Expr[T](Apply(
Select(tree, copy),
AssignOrNamedArg(Ident(TermName("id")), reify(id.splice).tree) :: Nil
))
}
}
есть способ, чтобы каким-то образом перенести определение типа таким образом, что макрос работает на себя субъекта User
и не тип? Поскольку это означает, что средство проверки типов ничего не знает о методе копирования класса case , поскольку все, что он видит, является значением типа E
.
Я хотел бы сделать:
val u = User(2,"foo")
u.withId(3)
Большинство из альтернативных решений, которые я видел влекут за собой определение withId, как абстрактные в черте Entity, а затем реализует метод в каждый случай класса, предпочли бы чтобы избежать этого, если это возможно.
у меня нет времени, чтобы смотреть на это подробно на данный момент, но вы видели [это мое сообщение в блоге] (http://meta.plasm.us/posts/2013/06/21/macro-methods-and-subtypes/)? –
@TravisBrown благодарит, что сделал мне еще один шаг, теперь можно делать 'u.withId (u, 3)'. Похоже, что контекст связан с тем, чтобы избежать необходимости проходить в том экземпляре, который у вас уже есть. Дайте ему повод в AM ... – virtualeyes
Кстати, вопрос о вашем посте @TravisBrown. Почему бы не использовать c.prefix.tree.tpe? –