Необходимо ссылаться на признак на объекте-компаньоне из признака в классе дел - PullRequest
0 голосов
/ 26 января 2019

Мне нужно получить доступ к классу-компаньону с указанной чертой - из черты, предназначенной для тематических классов.Я почти уверен, что библиотека отражений Scala может сделать это, но я не совсем смог собрать ее вместе.

Я создал тестовый код ниже, который требует один раздел ???быть наполненным некоторой магией отражения.Код компилируется и запускается как есть - с уведомлением из-за отсутствующей функциональности.

Некоторые связанные ответы, которые я видел в StackOverflow, были от 2.10.Совместимо с Scala 2.12, пожалуйста.

import scala.reflect.{ClassTag, classTag}

//for companion object
//accesses Fields of the associated case class to ensure the correctness
//note: abstract class -- not a trait due to issues using ClassTag on a trait
abstract class SupportsField1Companion[T: ClassTag] {
  //gets the names of all Fields on the associated case class
  val fieldNamesOfInstancedClass: Array[String] =
    classTag[T].runtimeClass.getDeclaredFields.map(_.getName)

  //prints the name and fields of the associated case class -- plus extra on success
  def printFieldNames(extra: String = ""): Unit = {
    val name = classTag[T].runtimeClass.getCanonicalName
    val fields = fieldNamesOfInstancedClass.reduceLeft(_ + ", " + _)
    println(s"Fields of $name: $fields" + extra)
  }
}

//for case classes
//IMPORTANT -- please do not parameterize this if possible
trait SupportsField1 {
  //some data for printing
  val field1: String = this.getClass.getCanonicalName + ": field1"

  //should get a reference to the associated companion object as instance of SupportsFieldsCompanion
  def getSupportsFieldsCompanion: SupportsField1Companion[this.type] = //this.type may be wrong
    ??? //TODO reflection magic required -- need functionality to retrieve companion object cast as type

  //calls a function on the associated Companion class
  def callPrintFuncOnCompanion(): Unit =
    getSupportsFieldsCompanion.printFieldNames(s" -- from ${this.getClass.getCanonicalName}")
}

//two case classes with the SupportsFieldsCompanion trait to ensure data is accessed correctly
object ExampleA extends SupportsField1Companion[ExampleA] {}
case class ExampleA() extends SupportsField1 {
  val fieldA: String = "ExampleA: fieldA"
}
object ExampleB extends SupportsField1Companion[ExampleB] {}
case class ExampleB() extends SupportsField1 {
  val fieldB: String = "ExampleB: fieldB"
}

object Run extends App {
  //create instanced classes and print some test data
  val exampleA = ExampleA()
  println(exampleA.field1) //prints "ExampleA: field1" due to trait SupportsFields
  println(exampleA.fieldA) //prints "ExampleA: fieldA" due to being of class ExampleA
  val exampleB = ExampleB()
  println(exampleB.field1) //prints "ExampleB: field1" due to trait SupportsFields
  println(exampleB.fieldB) //prints "ExampleB: fieldB" due to being of class ExampleB

  //via the SupportsFieldsCompanion trait on the companion objects,
  //call a function on each companion object to show that each companion is associated with the correct case class
  ExampleA.printFieldNames() //prints "Fields of ExampleA: fieldA, field1"
  ExampleB.printFieldNames() //prints "Fields of ExampleB: fieldB, field1"

  //test access of printFieldNames on companion object from instanced class
  try {
    exampleA.callPrintFuncOnCompanion() //on success, prints "Fields of ExampleA: fieldA, field1 -- from ExampleA"
    exampleB.callPrintFuncOnCompanion() //on success, prints "Fields of ExampleB: fieldB, field1 -- from ExampleB"
  } catch {
    case _: NotImplementedError => println("!!! Calling function on companion(s) failed.")
  }
}

1 Ответ

0 голосов
/ 26 января 2019

Существует множество способов сделать это, но, возможно, ниже приведен один из самых простых, который не предполагает предположений о том, как работает искаженное имя класса сопутствующего объекта Scala:

def getSupportsFieldsCompanion: SupportsField1Companion[this.type] =
  scala.reflect.runtime.ReflectionUtils.staticSingletonInstance(
    this.getClass.getClassLoader,
    this.getClass.getCanonicalName
  ).asInstanceOf[SupportsField1Companion[this.type]]

Это работаетпо желанию, но я, вероятно, набрал бы его как SupportsField1Companion[_], и в идеале я бы, вероятно, избегал использования открытых методов для SupportsField1, которые ссылаются на SupportsField1Companion - фактически в идеале . Я бы, вероятно, избежал этогоподход в целом, но если вы преданы делу, я думаю, что приведенное выше решение ReflectionUtil, вероятно, разумно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...