我需要一个异构的,类型安全的容器来存储不相关的类型A,B,C。
这是一种类型级别规范:
trait Container {
putA(a: A)
putB(b: B)
putC(c: C)
put(o: Any) = { o match {
case a: A => putA(a)
case b: B => putB(b)
case c: C => putC(c)
}
getAllAs : Seq[A]
getAllBs : Seq[B]
getAllCs : Seq[C]
}
哪种类型是支持此容器的最佳套件?
是否值得为类型A,B,C创建容错[T]类型类?
THKS。
答案 0 :(得分:7)
正如其他人所说,你可以利用无形的' Coproduct
类型。这是一个例子。
// let's define a Coproduct of the two types you want to support
type IS = Int :+: String :+: CNil
// now let's have a few instances
val i = Coproduct[IS](42)
val i2 = Coproduct[IS](43)
val s = Coproduct[IS]("foo")
val s2 = Coproduct[IS]("bar")
// let's put them in a container
val cont = List(i, s, i2, s2)
// now, do you want all the ints?
val ints = cont.map(_.select[Int]).flatten
// or all the strings?
val strings = cont.map(_.select[String]).flatten
// and of course you can add elements (it's a List)
val cont2 = Coproduct[IS](12) :: cont
val cont3 = Coproduct[IS]("baz") :: cont2
现在,这当然不是通用容器最直观的API,但可以使用Coproduct
轻松地将逻辑封装在自定义类中,以表示多种类型。
这是一个实现草图
import shapeless._; import ops.coproduct._
class Container[T <: Coproduct] private (underlying: List[T]) {
def ::[A](a: A)(implicit ev: Inject[T, A]) =
new Container(Coproduct[T](a) :: underlying)
def get[A](implicit ev: Selector[T, A]) =
underlying.map(_.select[A]).flatten
override def toString = underlying.toString
}
object Container {
def empty[T <: Coproduct] = new Container(List[T]())
}
实施例
scala> type IS = Int :+: String :+: CNil
defined type alias IS
scala> val cont = 42 :: "foo" :: "bar" :: 43 :: Container.empty[IS]
cont: Container[IS] = List(42, foo, bar, 43)
scala> cont.get[Int]
res0: List[Int] = List(42, 43)
scala> cont.get[String]
res1: List[String] = List(foo, bar)
答案 1 :(得分:2)
Miles Sabin在unboxed union types写了一篇文章;这是在CoProduct库中shapeless实现的:
shapeless具有
Coproduct
类型,ScalaEither
对任意数量的选择的推广
我绝对不是无形的专家,但如果您使用无形标记创建新问题或编辑您的问题,那么使用CoProduct
答案 2 :(得分:1)
你应该看看Shapeless的HList或Coproduct;我不会自己重塑这个。
答案 3 :(得分:0)
这是第一个版本,但我想抽象出类型:
trait Container {
def putInt(i: Int)
def putString(s: String)
def put(o: Any) = o match {
case i: Int => putInt(i)
case s: String => putString(s)
}
def getInts() : Seq[Int]
def getStrings() : Seq[String]
}
class MutableContainer extends Container {
val ints = mutable.ArrayBuffer[Int]()
val strings = mutable.ArrayBuffer[String]()
override def putInt(i: Int): Unit = ints += i
override def putString(s: String): Unit = strings += s
override def getStrings(): Seq[String] = strings
override def getInts(): Seq[Int] = ints
}
object TestContainer extends App {
val mc = new MutableContainer()
mc.put("a")
mc.put("b")
mc.put(1)
println(mc.getInts())
println(mc.getStrings())
}
现在尝试抽象出类型
trait Container {
def getInts() : Seq[Int]
def getStrings() : Seq[String]
def put[T](t: T)
//def get[T] : Seq[T]
}
class MutableContainer extends Container {
val entities = new mutable.HashMap[Class[_], mutable.Set[Any]]() with mutable.MultiMap[Class[_], Any]
override def getStrings(): Seq[String] = entities.get(classOf[String]).map(_.toSeq).getOrElse(Seq.empty).asInstanceOf[Seq[String]] //strings
override def getInts(): Seq[Int] = entities.get(classOf[Int]).map(_.toSeq).getOrElse(Seq.empty).asInstanceOf[Seq[Int]]
//override def get[T]: Seq[T] = entities.get(classOf[T]).map(_.toSeq).getOrElse(Seq.empty).asInstanceOf[Seq[T]]
override def put[T](t: T): Unit = entities.addBinding(t.getClass, t)
}
trait Containable[T] {
def typ : String
}
trait Cont {
implicit object IntContainable extends Containable[Int] {
override def typ: String = "Int"
}
implicit object StringContainable extends Containable[String] {
override def typ: String = "String"
}
}
object TestContainer extends App {
val mc = new MutableContainer()
mc.put("a")
mc.put("b")
mc.put(1)
println(mc.getInts())
println(mc.getStrings())
println(mc.entities.keys)
}
但是我遇到了java.lang.Integer和Int ...
的问题