Scala 通用通配符和特定类型
Scala generic wildcard and specific type
我有 mappings
值:
val mappings: Map[Class[_] ,Iterable[AttributeKeyAndValue] => AnyRef]
有没有可能像
一样让它更安全
val mappings: Map[Class[T], Iterable[AttributeKeyAndValue] => T]
其中 T
与下划线的作用相同。如果符合以下代码,我希望编译器会抱怨:
val mappings: Map[Class[T], Iterable[AttributeKeyAndValue] => T] = Map(
classOf[String], attrs => 1)
好吧,编译器不知道您提供的示例中的 T
是什么。
因此,作为一个选项,您可以定义 mappings
参数化的函数 T
:
def mappings[T](x: AttributeKeyAndValue => T):
Map[Class[T], AttributeKeyAndValue => T] = Map(classOf[T] -> x)
用法:
val mappping = mappings(x => x.toString)
并且编译器能够推断的类型是:
mappping : Map[Class[String], AttributeKeyAndValue => String]
你不能参数化 val
s 所以不,不是那样的。
看你的要求,没有多大意义。可以这样说:val mappings: Map[Class[T], Iterable[AttributeKeyAndValue] => T]
是有效的,编译器会抱怨。
您可以将地图中的所有条目参数化为相同类型,即。 T
或让每个条目都有自己的参数化类型,使得在使用 apply
或 get
方法检索条目时无法知道它是哪种类型。
我建议您坚持使用 Class[_]
,因为对其进行参数化的唯一方法是强制所有条目具有相同的类型。例如,如果您能够在 Map[Class[String], ...]
中对其进行参数化,那么您将只能在地图中放置 1 个条目,即键为 classOf[String]
的条目
Scala 中的通配符只是存在类型的一种特定的简单情况,而您想要的是更复杂的情况,因为您想在两个地方使用相同的 T
。类似于 Seq[(Class[T], AttributeKeyAndValue => T) forSome { type T }]
。但是注意你需要放forSome
的地方:如果你想要Map
,没有等价的地方!例如。 Map[Class[T], AttributeKeyAndValue => T] forSome { type T }
表示整个地图只有一个 T
。
我的建议是创建一个类型,它提供一个类型更安全的接口,即使你需要内部转换:
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
你实际上可以改进 API 以避免手动传递 类,所以你只需编写 get[String]
和 +(attrs => 1)
自动推断它需要 classOf[Int]
,但我决定在这里展示简单的想法。
把它包在盒子里 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
我有 mappings
值:
val mappings: Map[Class[_] ,Iterable[AttributeKeyAndValue] => AnyRef]
有没有可能像
一样让它更安全val mappings: Map[Class[T], Iterable[AttributeKeyAndValue] => T]
其中 T
与下划线的作用相同。如果符合以下代码,我希望编译器会抱怨:
val mappings: Map[Class[T], Iterable[AttributeKeyAndValue] => T] = Map(
classOf[String], attrs => 1)
好吧,编译器不知道您提供的示例中的 T
是什么。
因此,作为一个选项,您可以定义 mappings
参数化的函数 T
:
def mappings[T](x: AttributeKeyAndValue => T):
Map[Class[T], AttributeKeyAndValue => T] = Map(classOf[T] -> x)
用法:
val mappping = mappings(x => x.toString)
并且编译器能够推断的类型是:
mappping : Map[Class[String], AttributeKeyAndValue => String]
你不能参数化 val
s 所以不,不是那样的。
看你的要求,没有多大意义。可以这样说:val mappings: Map[Class[T], Iterable[AttributeKeyAndValue] => T]
是有效的,编译器会抱怨。
您可以将地图中的所有条目参数化为相同类型,即。 T
或让每个条目都有自己的参数化类型,使得在使用 apply
或 get
方法检索条目时无法知道它是哪种类型。
我建议您坚持使用 Class[_]
,因为对其进行参数化的唯一方法是强制所有条目具有相同的类型。例如,如果您能够在 Map[Class[String], ...]
中对其进行参数化,那么您将只能在地图中放置 1 个条目,即键为 classOf[String]
Scala 中的通配符只是存在类型的一种特定的简单情况,而您想要的是更复杂的情况,因为您想在两个地方使用相同的 T
。类似于 Seq[(Class[T], AttributeKeyAndValue => T) forSome { type T }]
。但是注意你需要放forSome
的地方:如果你想要Map
,没有等价的地方!例如。 Map[Class[T], AttributeKeyAndValue => T] forSome { type T }
表示整个地图只有一个 T
。
我的建议是创建一个类型,它提供一个类型更安全的接口,即使你需要内部转换:
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
你实际上可以改进 API 以避免手动传递 类,所以你只需编写 get[String]
和 +(attrs => 1)
自动推断它需要 classOf[Int]
,但我决定在这里展示简单的想法。
把它包在盒子里 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