1

mappings有价值:

val mappings: Map[Class[_] ,Iterable[AttributeKeyAndValue] => AnyRef]

是否有可能使它更类型安全

val mappings: Map[Class[T], Iterable[AttributeKeyAndValue] => T]

whereT与下划线的作用相同。如果它符合以下代码,我希望编译器会抱怨:

val mappings: Map[Class[T], Iterable[AttributeKeyAndValue] => T] = Map(
  classOf[String], attrs => 1)
4

4 回答 4

2

你不能参数化vals 所以不,不是那样的。

看你的要求,没有多大意义。可以说 this:val mappings: Map[Class[T], Iterable[AttributeKeyAndValue] => T]是有效的,编译器会抱怨。

您可以使用相同类型参数化地图中的所有条目,即。T或者让每个条目都有自己的参数化类型,从而在使用applyorget方法检索条目时无法知道它是哪种类型。

我建议您坚持使用,Class[_]因为对其进行参数化的唯一方法是强制所有条目具有相同的类型。例如,如果您能够对其进行参数化,Map[Class[String], ...]那么您将只能在地图中放置 1 个条目,即键所在的条目classOf[String]

于 2017-09-11T09:40:08.537 回答
2

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],但我决定在这里展示这个简单的想法。

于 2017-09-11T10:15:28.457 回答
0

好吧,编译器不知道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]
于 2017-09-11T09:37:12.503 回答
0

把它包装成一个案例类?

  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
于 2017-09-11T16:09:35.583 回答