从 Class[T] 映射到 T,无需强制转换 [英] Map from Class[T] to T without casting

查看:29
本文介绍了从 Class[T] 映射到 T,无需强制转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想按照以下代码行从类标记映射到实例:

I want to map from class tokens to instances along the lines of the following code:

trait Instances {
  def put[T](key: Class[T], value: T)
  def get[T](key: Class[T]): T
}

这是否可以在不必解析 get 方法中的强制转换的情况下完成?

Can this be done without having to resolve to casts in the get method?

更新:

对于使用 Foo[T] 而不是 Class[T] 的更一般情况,如何做到这一点?

How could this be done for the more general case with some Foo[T] instead of Class[T]?

推荐答案

如果您想在没有任何强制转换的情况下执行此操作(即使在 get 内),那么您需要写一个异构映射.出于显而易见的原因,这很棘手.:-) 最简单的方法可能是使用类似于 HList 的结构并构建一个 find 函数.但是,这并非微不足道,因为您需要定义某种方法来检查两种任意类型的类型相等性.

If you want to do this without any casting (even within get) then you will need to write a heterogeneous map. For reasons that should be obvious, this is tricky. :-) The easiest way would probably be to use a HList-like structure and build a find function. However, that's not trivial since you need to define some way of checking type equality for two arbitrary types.

我试图对元组和存在类型有点棘手.但是,Scala 不提供统一机制(模式匹配不起作用).此外,子类型将整个事物联系在一起,基本上消除了它可能提供的任何安全性:

I attempted to get a little tricky with tuples and existential types. However, Scala doesn't provide a unification mechanism (pattern matching doesn't work). Also, subtyping ties the whole thing in knots and basically eliminates any sort of safety it might have provided:

val xs: List[(Class[A], A) forSome { type A }] = List(
  classOf[String] -> "foo", classOf[Int] -> 42)

val search = classOf[String]
val finalResult = xs collect { case (`search`, result) => result } headOption

在这个例子中,finalResult 的类型是 Any.这实际上是正确的,因为子类型意味着我们对A 一无所知任何.这不是编译器选择该类型的原因,但这是一个正确的选择.举个例子:

In this example, finalResult will be of type Any. This is actually rightly so, since subtyping means that we don't really know anything about A. It's not why the compiler is choosing that type, but it is a correct choice. Take for example:

val xs: List[(Class[A], A) forSome { type A }] = List(classOf[Boolean] -> 'bippy)

这是完全合法的!子类型意味着 A 在这种情况下将被选择为 Any.这几乎不是我们想要的,但这是你会得到的.因此,为了表达这个约束而不跟踪所有单独的类型(使用 HMap),Scala 需要能够表达一个类型是一个类型的约束.特定类型,没有别的.不幸的是,Scala 没有这种能力,所以我们基本上停留在泛型约束方面.

This is totally legal! Subtyping means that A in this case will be chosen as Any. It's hardly what we want, but it is what you will get. Thus, in order to express this constraint without tracking all of the types individual (using a HMap), Scala would need to be able to express the constraint that a type is a specific type and nothing else. Unfortunately, Scala does not have this ability, and so we're basically stuck on the generic constraint front.

更新 实际上,这是不合法的.刚试了一下,编译器就把它踢出去了.我认为这只是因为 Class 的类型参数是不变的.所以,如果 Foo 是一个固定的类型,你应该是安全的.它仍然没有解决统一问题,但至少它是合理的.不幸的是,类型构造函数被假定为处于协变量、反变量和不变性之间的神奇叠加位置,所以如果它真正是一种 类型的任意类型 Foo* =>*,那么你仍然沉没在存在的前沿.

Update Actually, it's not legal. Just tried it and the compiler kicked it out. I think that only worked because Class is invariant in its type parameter. So, if Foo is a definite type that is invariant, you should be safe from this case. It still doesn't solve the unification problem, but at least it's sound. Unfortunately, type constructors are assumed to be in a magical super-position between co-, contra- and invariance, so if it's truly an arbitrary type Foo of kind * => *, then you're still sunk on the existential front.

总而言之:这应该是可能的,但前提是您将 Instances 完全编码为 HMap.就个人而言,我只会在 get 中进行转换.简单多了!

In summary: it should be possible, but only if you fully encode Instances as a HMap. Personally, I would just cast inside get. Much simpler!

这篇关于从 Class[T] 映射到 T,无需强制转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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