基本上,我需要异构地图,但我知道这不容易实现。
trait Box[T] {
def exec(): T
}
class IntBox extends Box[Int] {
def exec() = 69
}
class StringBox extends Box[String] {
def exec() = "foo"
}
因此,当我将Box
子类实例放入Map时,由于JVM的类型擦除,相关的类型参数就消失了。
val map = Map(0 -> new IntBox, 1 -> new StringBox)
val i: Any = map(0).exec() // compiles but not type safe and requires a cast later on
val ii: Int = map(0).exec() // compile error :(
// would work but in general it is not known at this point that type 'Int' is required
val iii: Int = map(0).exec().asInstanceOf[Int]
所以,问题是如何定义类型安全的 get 操作。请。请注意,Box
子类是由代码的最终用户提供的,因此,我无法控制存在多少Boxes
(因此,使用TypeTags
的个别匹配不是可能的)。
到目前为止,我试图找到一个TypeTags
的通用解决方案,但没有成功(通过向Box添加类型标记字段,但由于类型参数也被删除,我没有获得任何东西)。我很高兴修改exec
(或添加一个包装器),以便最终(一个总是成功的)演员可以完成 - 但我不确定如何获得正确的类型信息点。我也很乐意使用像Shapeless这样的库。 (但是,我很怀疑我是否可以使用无形hmap
,因为我无法提供所有可能的转换作为预先提示。我还发现了一些类型信息存储在密钥中的示例,但这对我的情况没有帮助,因为当我能够以类型安全的方式从另一个数据结构获取密钥时,我也可以为首先是价值观。任何提示?
答案 0 :(得分:0)
我们讨论过这个,但为了完整起见,我的回答是:
import scala.util.Try
class AnyMap(map: Map[Int, Any] = Map.empty) {
def add[A](int: Int, a: A): AnyMap =
new AnyMap(map + (int -> (a: Any)))
def tryGet[A](int: Int): Try[A] = Try(map(int).asInstanceOf[A])
}
这只是向上转换所有值并将它们推向同一个值
Map[Int, Any]
,然后在检索时向下转发。
使用示例:
val anyMap = new AnyMap
anyMap.add(0, 1).add(1, true).tryGet[Boolean](1)
输出:
Try[Boolean] = Success(true)
我认为这是相当合理的,因为我们已经习惯了 在Scala中传递类型参数的各种地方;不得不 传递参数实际上应该作为一个有用的提醒,我们是 在这里做一些与众不同的事情。事实上,多亏了类型 推理有时我们可以指定整个表达式的返回类型 并避免将显式类型参数传递给方法调用:
val tryValue: Try[Boolean] = anyMap.add(0, 1).add(1, true).tryGet(1)
输出:
tryValue: Try[Boolean] = Success(true)