Chciałbym zaprogramować makro Scala, które pobiera wystąpienie klasy case jako argumentu. Wszystkie obiekty, które można przekazać do makra, muszą zaimplementować określoną cechę znacznika.Introspect argument przekazany do makro Scala
Poniższy fragment pokazuje cecha marker i dwie klasy przykładowym przypadku wdrożenia go:
trait Domain
case class Country(id: String, name: String) extends Domain
case class Town(id: String, longitude: Double, latitude: Double) extends Domain
Teraz chciałbym napisać następujący kod za pomocą makra, aby uniknąć ciężkość refleksji wykonawczego i jego wątku unsafety:
object Test extends App {
// instantiate example domain object
val myCountry = Country("CH", "Switzerland")
// this is a macro call
logDomain(myCountry)
}
makro logDomain
realizowany jest w innym projekcie i wygląda podobnie do:
object Macros {
def logDomain(domain: Domain): Unit = macro logDomainMacroImpl
def logDomainMacroImpl(c: Context)(domain: c.Expr[Domain]): c.Expr[Unit] = {
// Here I would like to introspect the argument object but do not know how?
// I would like to generate code that prints out all val's with their values
}
}
Celem makro powinno być generowania kodu, który - w czasie pracy - wyjścia wszystkich wartości (id
i name
) danego obiektu i wyświetla je jak przedstawiono poniżej:
id (String) : CH
name (String) : Switzerland
Aby to osiągnąć, muszę do dynamicznego sprawdzania argumentu przekazanego typu i określania jego członków (vals). Następnie musiałbym wygenerować AST reprezentujący kod, który tworzy dane wyjściowe dziennika. Makro powinno działać niezależnie od tego, jaki konkretny obiekt implementuje cechę znacznika "Domena" jest przekazywany do makra.
W tym momencie jestem zagubiony. Byłbym wdzięczny, gdyby ktoś dał mi punkt wyjścia lub wskazał mi jakąś dokumentację? Jestem stosunkowo nowy w Scali i nie znalazłem rozwiązania w dokumentach API Scala lub w przewodniku Makro.
Pokonałeś mnie 5 minut! :) –
Wielkie dzięki za szczegółową odpowiedź! Twój przykład robi dokładnie to, czego szukałem. Wypróbuję to dziś wieczorem. To, co jest dobre w twoim rozwiązaniu, to użycie parametru type i WeakTypeTag, który sprawia, że kod jest całkowicie ogólny. Powinien działać dla każdej klasy przypadków implementującej "domenę". – MontChanais