[英]Scala generic wildcard and specific type
I have the mappings
value: 我有
mappings
值:
val mappings: Map[Class[_] ,Iterable[AttributeKeyAndValue] => AnyRef]
is it possible to make it more typesafe like 是否有可能使其更加类型安全
val mappings: Map[Class[T], Iterable[AttributeKeyAndValue] => T]
where T
plays the same role as underscore. 其中
T
与下划线相同。 I'd expect compiler to complain, if it meets this code: 如果它符合以下代码,我希望编译器会抱怨:
val mappings: Map[Class[T], Iterable[AttributeKeyAndValue] => T] = Map(
classOf[String], attrs => 1)
You can't parametrize val
s so no, not like that. 您不能参数化
val
所以不能,不是那样。
Looking at your request, it doesn't make much sense. 看着你的要求,没有多大意义。 Lets say that this:
val mappings: Map[Class[T], Iterable[AttributeKeyAndValue] => T]
was valid and the compiler would complain. 可以这样说:
val mappings: Map[Class[T], Iterable[AttributeKeyAndValue] => T]
是有效的,编译器会抱怨。
You would either parametrize all the entries in the map with the same type, ie. 您可以参数化映射中具有相同类型的所有条目,即。
T
or have each entry with it's own parametrized type making it impossible to know which type it is when retrieving the entries with the apply
or get
methods. T
或每个条目都有其自己的参数化类型,从而在使用apply
或get
方法检索条目时无法知道它是哪种类型。
I suggest you stick with the Class[_]
because the only way to parametrize this is to force all the entries to have the same type. 我建议您坚持使用
Class[_]
因为对此进行参数化的唯一方法是强制所有条目具有相同的类型。 For example if you were able to parametrize it in Map[Class[String], ...]
then you would only be able to put 1 entry in the map, the one where the key is classOf[String]
例如,如果您可以在
Map[Class[String], ...]
对其进行参数化Map[Class[String], ...]
那么您将只能在地图中放置1个条目,其中键为classOf[String]
那个条目
Wildcards in Scala are just a specific simple case of existential types, and what you want would be a more complex one because you want to use the same T
in two places. Scala中的通配符只是存在类型的一种特定的简单情况,而您想要的则更复杂,因为您想在两个地方使用相同的
T
Something like Seq[(Class[T], AttributeKeyAndValue => T) forSome { type T }]
. 像
Seq[(Class[T], AttributeKeyAndValue => T) forSome { type T }]
。 But note where you need to put forSome
: there is no equivalent place if you want Map
! 但是请注意您需要放置
forSome
:如果想要Map
,就没有等效的位置! Eg Map[Class[T], AttributeKeyAndValue => T] forSome { type T }
would mean there is a single T
for the entire map. 例如
Map[Class[T], AttributeKeyAndValue => T] forSome { type T }
表示整个地图只有一个T
What I'd suggest is creating a type which presents a more type-safe interface, even if you need casts inside: 我建议创建一个呈现更类型安全的接口的类型,即使您需要在内部进行强制转换:
class Mappings private (contents: Map[Class[_], Iterable[AttributeKeyAndValue] => AnyRef]) {
def get[T](clazz: Class[T]) = contents.get(clazz).asInstanceOf[Option[Iterable[AttributeKeyAndValue] => T]]
def +[T](clazz: Class[T], value: Iterable[AttributeKeyAndValue] => T) = new Mappings(contents + (clazz, value))
// any other methods you want
}
object Mappings {
val empty = new Mappings(Map.empty)
}
// elsewhere
Mappings.empty + (classOf[String], attrs => "a") // type-checks
Mappings.empty + (classOf[String], attrs => 1) // doesn't type-check
You can actually improve the API to avoid manually passing classes, so you just write get[String]
and +(attrs => 1)
automatically infers it needs classOf[Int]
, but I decided to show the simple idea here. 实际上,您可以改进API以避免手动传递类,因此您只需编写
get[String]
和+(attrs => 1)
自动推断出它需要classOf[Int]
,但是我决定在这里展示一个简单的想法。
Well, compiler does not know what is T
in example you've provided. 好了,编译器不知道您提供的示例中的
T
是什么。 So, as an option you can defined mappings
function parametrised by T
: 因此,作为一种选择,您可以定义由
T
参数化的mappings
函数:
def mappings[T](x: AttributeKeyAndValue => T):
Map[Class[T], AttributeKeyAndValue => T] = Map(classOf[T] -> x)
usage: 用法:
val mappping = mappings(x => x.toString)
and the type that compiler will be able to infer is: 编译器可以推断的类型是:
mappping : Map[Class[String], AttributeKeyAndValue => String]
Wrap it around into a case class? 将其包装成案例类吗?
type Attrs = Iterable[AttributeKeyAndValue]
case class Mappings[T](m: Map[Class[T], Attrs => T]
object Mappings {
implicit def mk[T](m: Map[Class[T], Attrs => T): Mappings[T] = Mappings(m)
}
val mappings: Mappings[_] = Map(classOf[String] -> { (_:Attrs) => "foo" }) // Works
val badMappings: Mappings[_] = Map(classOf[String] -> { (_:Attrs) => 1 }) // Fails
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.