Scala принимает только общий тип String или Int в списке - PullRequest
0 голосов
/ 28 октября 2018

У меня есть класс дел, определенный как ниже

case class ChooseBoxData[T](index:T, text:String)

Можно ли объявить список так, чтобы список принимал только типы ChooseBoxData [String] и ChooseBoxData [Int]?

То, что я ожидал, выглядит примерно так:

val specialList:List[some type declaration] = List(
  ChooseBoxData[String]("some string","some string"),/* allow, because is ChooseBoxData[String]*/
  ChooseBoxData[Int](12,"some string"), /* also allow, because is ChooseBoxData[Int]*/
  ChooseBoxData[Boolean](true,"some string")/* not allow type other than ChooseBoxData[String] or ChooseBoxData[Int]*/
)

Ответы [ 4 ]

0 голосов
/ 28 октября 2018

Примерно такобъявляя аргумент функции, а не просто переменную, было бы более элегантное решение:

trait CanUse[T]
implicit case object CanUseInt extends CanUse[Int]
implicit case object CanUseString extends CanUse[String]

def foo[T : CanUse](bar: List[ChooseBoxData[T]])
0 голосов
/ 28 октября 2018

Вы можете создать дополнительное ограничение поверх класса вашего дела.

import language.implicitConversions

case class ChooseBoxData[T](index:T, text:String)

trait MySpecialConstraint[T] {
  def get: ChooseBoxData[T]
}

implicit def liftWithMySpecialConstraintString(cbd: ChooseBoxData[String]) =
  new MySpecialConstraint[String] {
    def get = cbd
  }

implicit def liftWithMySpecialConstraintInt(cbd: ChooseBoxData[Int]) =
  new MySpecialConstraint[Int] {
    def get = cbd
  }


// Now we can just use this constraint for out list 
val l1: List[MySpecialConstraint[_]] = List(ChooseBoxData("A1", "B1"), ChooseBoxData(2, "B2"))
0 голосов
/ 28 октября 2018

Почему вы не можете сделать это так:

object solution extends App {

  case class ChooseBoxData[T](index: T, text: String) extends GenericType[T]

  trait GenericType[T] {
    def getType(index: T, text: String): ChooseBoxData[T] = ChooseBoxData[T](index, text)
  }

  val specialList = List(
    ChooseBoxData[String]("some string", "some string"),
    ChooseBoxData[Int](12, "some string"), 
    ChooseBoxData[Boolean](true, "some string")
  )

  println(specialList)
}

//output: List(ChooseBoxData(some string,some string), ChooseBoxData(12,some string), ChooseBoxData(true,some string))
0 голосов
/ 28 октября 2018

Вот что я придумал:

Сначала мы создаем следующие алгебраические типы данных (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))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...