简体   繁体   中英

How to create a list of generic case classes in Scala?

In my web app, a user uploads different kinds of data to our server: string, excel files, ints. I want to assemble all this data in one list if possible:

object CacheII extends App{
  case class Data[TypeT](kind: String, data: TypeT)

  val item1 = Data("type1", "data1")
  val item2 = Data("type1", "data2")
  val item3 = Data("type2", "data1".getBytes())
  val item4 = Data("type2", "data2".getBytes())

  val list = List(item1, item2, item3, item4)

  val item5 = if(true)
    Data("type2", "data1".getBytes())
  else if(true)
    Data("type1", "data1")
  else
    Data("type3", 548)

  def addItem(list: List[Data[Any]], item: Data[Any]) = {
    list :+ item
  }

  println(addItem(list, item5))
}

Compiler Error:

Error:(22, 19) type mismatch;
 found   : List[CacheII.Data[_ >: Array[Byte] with String <: java.io.Serializable]]
 required: List[CacheII.Data[Any]]
  println(addItem(list, item5))
                  ^

How to correctly create such a list of the user data? Is there a different/better way to do this?

Any advice is appreciated.

Thank you.

You can create a list using covariant TypeT . But general way to approach this problem is using ADTs

sealed trait Data

case class StringData(value: String) extends Data

case class ByteData(value: Array[Byte]) extends Data

and so on ....

Benefits

  1. Pattern matching extraction.

  2. Compiler error/warning when certain case is missed.

  3. Less error prone

  4. Auto complete support to generate all cases from IntelliJ idea and other IDEs

  5. Elegant

Scala REPL

Adding different new data items to old list

scala> :paste
// Entering paste mode (ctrl-D to finish)

    sealed trait Data

    case class StringData(value: String) extends Data

    case class ByteData(value: Array[Byte]) extends Data

// Exiting paste mode, now interpreting.

defined trait Data
defined class StringData
defined class ByteData

scala> val oldList = List(StringData("stackoverflow"), ByteData("scala".getBytes))
oldList: List[Product with Serializable with Data] = List(StringData(stackoverflow), ByteData([B@108b121f))

scala> def addItem(oldList: List[Data], newItem: Data): List[Data] = oldList ++ List(newItem)
addItem: (oldList: List[Data], newItem: Data)List[Data]

scala> addItem(oldList, StringData("cow goes moo"))
res1: List[Data] = List(StringData(stackoverflow), ByteData([B@108b121f), StringData(cow goes moo))

Simply make Data covariant:

case class Data[+TypeT](kind: String, data: TypeT)

You can read more about variances at https://docs.scala-lang.org/tour/variances.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM