簡體   English   中英

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)

您不能參數化val所以不能,不是那樣。

看着你的要求,沒有多大意義。 可以這樣說: val mappings: Map[Class[T], Iterable[AttributeKeyAndValue] => T]是有效的,編譯器會抱怨。

您可以參數化映射中具有相同類型的所有條目,即。 T或每個條目都有其自己的參數化類型,從而在使用applyget方法檢索條目時無法知道它是哪種類型。

我建議您堅持使用Class[_]因為對此進行參數化的唯一方法是強制所有條目具有相同的類型。 例如,如果您可以在Map[Class[String], ...]對其進行參數化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] ,但是我決定在這里展示一個簡單的想法。

好了,編譯器不知道您提供的示例中的T是什么。 因此,作為一種選擇,您可以定義由T參數化的mappings函數:

       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]

將其包裝成案例類嗎?

  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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM