Refleksi runtime scala mendapatkan semua anggota tipe tertentu bahkan untuk kelas dalam

Dec 16 2020

Dengan scala 2.12.10

Misalkan saya ingin mengubah secara implisit saat runtime kelas kasus, dalam hal ini Specialmenjadi kelas kasus SpecialString. Konversi tersirat disediakan oleh suatu sifat External. Nama untuk SpecialStringharuslah nama deklarasi kelas Special.

import scala.reflect.runtime.universe.{runtimeMirror, typeOf}
import scala.reflect.runtime.universe


case class Special(i: Int)
case class SpecialString(s: String)

trait External {
  val rm = runtimeMirror(getClass.getClassLoader)
  val im = rm.reflect(this)
  val members = im.symbol.typeSignature.members
  def specials: Iterable[universe.Symbol] = members.filter(_.typeSignature <:< typeOf[Special] )
  implicit def SpecialIntToString(s: Special): SpecialString = {
    val name = im.reflectField(specials.filter(x => im.reflectField(x.asTerm).get.asInstanceOf[Special] == s).head.asTerm).symbol.toString.replace("value ", "")
    SpecialString(s"name = $name")
  }
}

Saat ini saya dapat secara implisit mengubah anggota yang dinyatakan di dalam kelas yang memperluas Externalsifat tersebut.

class MyClass extends External {
  val firstSpecial = Special(1)
  val two = 2
  val specialS: SpecialString = firstSpecial
}

class MySecondClass extends MyClass {
  val specialS2: SpecialString = firstSpecial
}
val myClass = new MyClass
print(myClass.specialS) // SpecialString(name = firstSpecial)

Tapi saya tidak dapat mengonversi anggota yang dideklarasikan di kelas super

class MyClass {
  val firstSpecial = Special(1)
  val two = 2
  val specialS: SpecialString = firstSpecial
}

class MySecondClass extends MyClass with External {
  val specialS2: SpecialString = firstSpecial
}
val myClass = new MyClass
print(myClass.specialS)
val mySecondClass = new MySecondClass
print(mySecondClass.specialS2) // java.util.NoSuchElementException: next on empty iterator

Ada bantuan?

Jawaban

1 DmytroMitin Dec 17 2020 at 11:51

Jika Anda menemukan anggota yang diperlukan berdasarkan nama daripada typeSignature(dan itu benar-benar ditemukan kemudian) dan cetak specials.head.typeSignaturedan typeOf[Special]Anda akan melihat mengapa salah satu bukan subtipe dari yang lain

trait External {
  ...
  def specials: Iterable[universe.Symbol] =
    members.filter(_.name == universe.TermName("firstSpecial") )
    //members.filter(_.typeSignature.resultType <:< typeOf[Special] )
  println(s"specials.head.typeSignature=${specials.head.typeSignature}=${universe.showRaw(specials.head.typeSignature)}")
  println(s"typeOf[Special]=${typeOf[Special]}=${universe.showRaw(typeOf[Special])}")
  println(s"specials.head.typeSignature <:< typeOf[Special]=${specials.head.typeSignature <:< typeOf[Special]}")
  ...
}

//specials.head.typeSignature=pckg.App.Special=NullaryMethodType(TypeRef(ThisType(pckg.App), pckg.App.Special, List()))
//typeOf[Special]            =pckg.App.Special=TypeRef(ThisType(pckg.App), pckg.App.Special, List())
//specials.head.typeSignature <:< typeOf[Special]=false

Jenis metode nullary yang dikembalikan Specialbukan merupakan subtipe dari Special.

Anda harus menambahkan resultType. Menggantikan

trait External {
  ...
  def specials: Iterable[universe.Symbol] =
    members.filter(_.typeSignature <:< typeOf[Special] )

dengan

trait External {
  ...
  def specials: Iterable[universe.Symbol] =
    members.filter(_.typeSignature.resultType <:< typeOf[Special])

Bagaimana menemukan tipe data parameter kelas saat runtime dalam skala