Создание подклассов HashMap в Scala, работа с стиранием типов - PullRequest
4 голосов
/ 25 августа 2011

Допустим, по какой-то веской причине я хочу универсальный HashMap, который содержит все типы объектов. Я также хочу вставить любые неприглядные instanceof подобные проверки типов в структуру данных. Для этого было бы неплохо иметь такой метод, как getAs[T <: Any](key: String): Option[T].

class State extends HashMap[String, Any] {

  override def +[T >: Any](elem: (String, T)): State = super.+(elem)
  override def -(key: String): State = super.-(key)

  def getAs[T](key: String): Option[T] = {
    super.get(key) match {
      case s: Some[T] => s
      case _ => None
    }
  }

}
object State extends HashMap[String, Any] {
  override def empty: State = super.empty
}

У меня также есть следующее неявное преобразование, определенное в объекте пакета:

implicit def fromHashMap(m: HashMap[String, Any]): State = m.asInstanceOf[State]

Когда я компилирую вышеприведенный код, я получаю следующее предупреждение типа:

State.scala:10: warning: non variable type-argument T in type pattern Some[T] is
unchecked since it is eliminated by erasure
case s: Some[T] => s
        ^

Это прискорбно, так как вся цель этого утверждения, если проверить тип!

В этом случае у меня есть другой вариант, кроме использования экспериментальных функций Манифеста? Кроме того, есть ли лучший базовый подход для достижения этой цели?

Edit:

Я получил это, работая с Манифестами. Мне очень помогла эта статья о Stackoverflow. Тем не менее, мне все еще любопытно, есть ли способ, который кто-нибудь может порекомендовать.

Двойное редактирование:

Вот текущая версия этого. Манифесты решили мои неотложные вопросы. Тем не менее, главное изменение, которое я сделал, - сделать класс State оболочкой для карты. При этом я утратил преимущества наследования (то есть теперь я должен явным образом раскрыть каждый метод карты, который мне нужен a keySet ниже.

class State(
  map: HashMap[String, (Manifest[_], Any)] = 
    scala.collection.immutable.HashMap.empty[String, (Manifest[_], Any)]
) extends java.io.Serializable {

  def +[T <: Any](elem: (String, T))(implicit m: Manifest[T]): State =
    State(map.+((elem._1, (m, elem._2))))

  def -(key: String): State = State(map.-(key))

  def keySet = map.keySet

  def getAs[T](key: String)(implicit m : Manifest[T]): Option[T] = {
    map.get(key) match {
      case Some((om: Manifest[_], o: Any)) =>
        if (om <:< m) Some(o.asInstanceOf[T]) else None
      case _ => None
    }
  }

}

object State {
  def apply() = new State()
  def apply(map: HashMap[String, (Manifest[_], Any)]) = new State(map)
  def empty = State()
}

Спасибо всем, кто до сих пор смотрел на это.

Обновление для Scala 2.10:

Смотрите текущую реализацию State, используя ClassTag и друзей здесь, на GitHub . Я планирую обновить его, чтобы использовать TypeTag s после того, как TypeCreator s станет сериализуемым.

1 Ответ

2 голосов
/ 26 августа 2011

Обратите внимание, что пока

case s: Some[T]

Не работает, потому что параметр типа Some удален, это другое:

case s @ Some(_: T)

В этом случае это не работает, потому что T сам является параметром типа. Хотя это не имеет значения в вашем случае (нет, нет другого пути, кроме манифестов), рассмотрите следующее:

case s: Some[Int]      // erased
case s @ Some(_: Int)  // not erased
...