如何在Scala中实现异构容器 [英] How to implement an heterogeneous container in Scala

查看:233
本文介绍了如何在Scala中实现异构容器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要一个异构的,类型安全的容器来存储不相关的A,B,C类。

I need an heterogeneous, typesafe container to store unrelated type A, B, C.

这里是一种类型级别的规范:

Here is a kind of type-level specification :

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]
}

哪种类型是最适合支持此容器的套件?

Which type is best suites to backed this container ?

值得创建一个Containerable [T]类型类型为类型A,B,C?

Is it worth creating a Containerable[T] typeclass for types A, B, C ?

thks。

推荐答案

像其他人建议的,你可以利用shapeless' Coproduct 类型。这是一个例子。

As other have suggested, you can leverage shapeless' Coproduct type. Here's an example.

// 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 来封装自定义类中的逻辑多种类型。

Now this is of course not the most intuitive API for a generic container, but can easily encapsulate the logic inside a custom class using a Coproduct for representing the multiple types.

这是一个实现的草图

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)

这篇关于如何在Scala中实现异构容器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆