Класс экземпляра case из сопутствующего объекта

Имею следующее:

trait C {}

object O {
    case class Foo(bar: String) extends C
}

И я хотел бы создать экземпляр Foo из String. До того момента, как я создал экземпляр Foo, но я не могу выполнить приведение к C. Я использую:

val ob = runtimeMirror.staticModule("O.Foo")
val foo = runtimeMirror.reflectModule(ob).instance

Теперь foo является экземпляром O.Foo, но его нельзя преобразовать в C.

val c = foo.asInstanceOf[C] 

Эта самая последняя строка возвращает:

O$foo$ cannot be cast to C

person ie8888    schedule 13.08.2017    source источник
comment
Использование отражения редко бывает хорошим решением, а использование asInstanceOf еще меньше. Скорее используйте заводской шаблон (например, stackoverflow.com/a/45654971/3347384)   -  person cchantep    schedule 13.08.2017
comment
Я думаю, что C является надстройкой экземпляров Foo, а не сопутствующим объектом O.Foo, о котором вы говорите.   -  person Gábor Bakos    schedule 13.08.2017
comment
@cchantep спасибо, но у меня это не работает. @ GáborBakos, пожалуйста, еще раз посмотрите мой код, я хочу создать экземпляр класса case Foo, который имеет как supertrait C, у меня нет сопутствующего объекта для Foo   -  person ie8888    schedule 14.08.2017
comment
@ ie8888 ничто не мешает вам добавить компаньона, что является довольно распространенной / хорошей практикой в ​​Scala (в отличие от использования отражения, которое является довольно плохой практикой, даже в ванильной Java)   -  person cchantep    schedule 14.08.2017
comment
@ ie8888, код вашего вопроса не работает так, как вы думаете. Он получает объект O.Foo, который является сопутствующим объектом class O.Foo. Вы не создаете новый экземпляр, вы просто получаете уже существующего компаньона. Если вы действительно сделали O.Foo, то приведение к C будет успешным, но вы получите только O.Foo.type, который не является C.   -  person HTNW    schedule 14.08.2017
comment
Вы совершенно правы @HTNW. Теперь я понимаю, почему это не работает. Спасибо   -  person ie8888    schedule 15.08.2017


Ответы (2)


Решение оказалось намного проще, чем я думал.

Class.forName("O$Foo").newInstance

Следует отметить, что для этого решения требуется, чтобы Foo имел конструктор без аргументов. Это последнее условие не является проблемой для моего кода, поэтому оно решено.

person ie8888    schedule 14.08.2017

Классы случаев, расширяющие признак, будут реализованы только в своем классе, а не в своем сопутствующем объекте, например, см.:

trait C {}

object O {
  case class Foo(bar: String) extends C
  case class Foo2(bar: String) extends C
  object Foo2 extends C
}

object Q extends App {
  import scala.reflect.runtime.universe._
  val rm = runtimeMirror(getClass.getClassLoader)

  for (ref <- Seq("O.Foo", "O.Foo2")) {
    val ob = rm.staticModule(ref)
    val foo = rm.reflectModule(ob).instance
    println(foo.isInstanceOf[C])
  }
}

Это печатает:

ложный

правда

Когда вы ссылаетесь на staticModules, вы имеете в виду сопутствующие объекты, поэтому C не реализуется классом, который вы тестировали.

person Gábor Bakos    schedule 13.08.2017