Вот что я придумал:
Сначала мы создаем следующие алгебраические типы данных (ADT):
sealed trait StringInt
case class Stringy(s : String) extends StringInt
case class Inty(s : Int) extends StringInt
И определяем ChoooseBoxData
следующим образом:
case class ChooseBoxData(index : StringInt, text : String)
Затем мы определяем следующие последствия для преобразования Int
и String
в области видимости в определенный ADT:
object CBImplicits {
implicit def conv(u : String) = Stringy(u)
implicit def conv2(u : Int) = Inty(u)
}
Теперь мы можем выполнить требование в вопросе.Вот пример:
import CBImplicits._
val list = List(ChooseBoxData("str", "text"),
ChooseBoxData(1, "text"),
ChooseBoxData(true, "text"))
При попытке выполнить вышеизложенное компилятор будет жаловаться на несоответствие типов.Но это скомпилирует и запустит:
List(
ChooseBoxData("str", "text"),
ChooseBoxData(1, "text"),
ChooseBoxData(12, "text2"))
, что приведет к:
a: List[ChooseBoxData] =
List(ChooseBoxData(Stringy(str),text), ChooseBoxData(Inty(1),text), ChooseBoxData(Inty(12),text2))
Это сохранит информацию о типе index
(конечно, обернутую в StringInt
супертип), которая позже может бытьлегко извлекается с помощью сопоставления с шаблоном для отдельных элементов.
Обертку также легко удалить для всех элементов, но в результате тип index
станет Any
, чего мы и ожидали, потому что Any
является наименьшим общим предком для String
и Int
в иерархии классов Scala.
РЕДАКТИРОВАТЬ: решение, использующее Shapeless
import shapeless._
import syntax.typeable._
case class ChooseBoxData[T](index : T, text : String)
val a = ChooseBoxData(1, "txt")
val b = ChooseBoxData("str", "txt")
val c = ChooseBoxData(true, "txt")
val list = List(a, b, c)
val `ChooseBoxData[Int]` = TypeCase[ChooseBoxData[Int]]
val `ChooseBoxData[String]` = TypeCase[ChooseBoxData[String]]
val res = list.map {
case `ChooseBoxData[Int]`(u) => u
case `ChooseBoxData[String]`(u) => u
case _ => None
}
//result
res: List[Product with Serializable] = List(ChooseBoxData(1,txt), ChooseBoxData(str,txt), None)
Таким образом, он разрешает компиляцию, но заменит недействительные экземпляры на None
(который затем может быть использован для выдачи ошибки времени выполнения при желании), или вы можете напрямую фильтровать нужные экземпляры, используя:
list.flatMap(x => x.cast[ChooseBoxData[Int]])
//results in:
List[ChooseBoxData[Int]] = List(ChooseBoxData(1,txt))