Вы можете использовать «разнородную карту». Гетерогенная карта - это карта, в которой ключи и значения могут иметь разные типы. Я не знаю ни одной существующей реализации типогенной гетерогенной карты, которая удовлетворяла бы вашим потребностям, но вот действительно простая реализация. Я думаю, что вы действительно хотите, это возможность использовать стандартные операции сбора на этой забавной карте, и это должно помочь с этим.
import scala.language.existentials
import scala.collection._
class HMap[K[_], V[_]](underlying: immutable.Map[K[_], V[_]] = immutable.Map.empty[K[_], V[_]])
extends Iterable[(K[T], V[T]) forSome { type T }]
with IterableOps[(K[T], V[T]) forSome { type T }, Iterable, HMap[K, V]] {
// collections boilerplate
override protected def fromSpecific(coll: IterableOnce[(K[T], V[T]) forSome { type T }]): HMap[K, V]
= new HMap[K, V](immutable.Map.from(coll))
override protected def newSpecificBuilder: mutable.Builder[(K[T], V[T]) forSome { type T }, HMap[K, V]]
= immutable.Map.newBuilder[K[_], V[_]].mapResult(new HMap[K, V](_))
override def empty: HMap[K, V] = new HMap[K, V]
override def iterator: Iterator[(K[T], V[T]) forSome { type T }]
= new Iterator[(K[T], V[T]) forSome { type T }] {
val underlying = HMap.this.underlying.iterator
override def hasNext: Boolean = underlying.hasNext
override def next(): (K[T], V[T]) forSome { type T }
= underlying.next().asInstanceOf[(K[T], V[T]) forSome { type T}]
}
// Mappy operations
def get[T](k: K[T]): Option[V[T]] = underlying.get(k).map(_.asInstanceOf[V[T]])
def +[T](kv: (K[T], V[T])): HMap[K, V] = new HMap[K, V](underlying + kv)
def -[T](k: K[T]): HMap[K, V] = new HMap[K, V](underlying - k)
}
object HMap {
// Mappy construction
def apply[K[_], V[_]](elems: (K[T], V[T]) forSome { type T }*): HMap[K, V] = new HMap[K, V](immutable.Map(elems: _*))
}
Теперь все работает довольно аккуратно
type FieldOf[T] = Field[T, _ <: Type[T]]
type Id[T] = T
val map = HMap[FieldOf, Id](
field1 -> "abc",
field2 -> boolean2Boolean(true)
// field2 -> new AnyRef // doesn't work, readable(-ish) error message
)
val dataBuilder = new DataBuilder
map.foreach { case (key, value) => dataBuilder.addEntry(key, value) }
Если экзистенциалы доставляют вам неудобства, следует заменить (K[T], V[T]) forSome { type T }
на Prod[K, V, _]
, где
case class Prod[K[_], V[_], T](k: K[T], v: V[T])
object Prod {
implicit def fromTup2[K[_], V[_], T](kv: (K[T], V[T])): Prod[K, V]
= Prod(kv._1, kv._2)
}
(при необходимости внесите еще несколько изменений)