Scala: избежать стирания типа - PullRequest
0 голосов
/ 17 октября 2019

Из следующего кода:

type Structure = Map[String, Any]

def getStructureSourceNames(structuresDesc: Structure): Iterable[String] = {
  val subColsDesc: Map[String, String] =
    structuresDesc.filter(_._2.isInstanceOf[String]).asInstanceOf[Map[String, String]]
  val subStructuresDesc: Map[String, Structure] = structuresDesc
    .filter(_._2.isInstanceOf[Map[String, Structure]])
    .asInstanceOf[Map[String, Structure]]

  subColsDesc.values ++ subStructuresDesc.values.flatMap(getStructureSourceNames(_))
}

Я хочу передать рекурсивную карту (String -> String), т.е. Пример структуры:

Map("test" -> Map(
        "newid" -> "id",
        "newstring" -> "string",
        "toto" -> Map("newdouble" -> "double")
      ),
      "otherid" -> "id")

Метод getStructureSourceNames должен возвращать список «окончательных» значений, т.е. просмотрите все дерево и для каждого листа получите значение String.

Когда я запускаю этот код, это заставляет меня:

Warning:(78, 32) non-variable type argument String in type scala.collection.immutable.Map[String,Structure] (the underlying of Map[String,Structure]) is unchecked since it is eliminated by erasure
  .filter(_._2.isInstanceOf[Map[String, Structure]])

Более того, я не люблю использовать isInstanceOf/ asInstanceOf. Погуглив, я обнаружил, что могу использовать сопоставление с образцом для проверки типа и получить карту с ожидаемой типизацией, но не могу найти, как это сделать.

Не могли бы вы привести пример такого кода?

1 Ответ

3 голосов
/ 17 октября 2019

Существует 2 вида сопоставления с образцом:

1) сопоставление с образцом при сопоставлении с шаблоном sealed trait (хорошо)

2), где шаблоны включают сопоставление с произвольными классами и проверки на равенство (не лучше чем instanceOf чеки)

Чтобы избежать 2), вам нужно сделать тип, который вы хотите, чтобы соответствовать запечатанной черте:

sealed trait ConfigValue
case class StringValue(v: String) extends ConfigValue
case class MapValue(map: Map[String, ConfigValue]) extends ConfigValue

val struct: ConfigValue = MapValue(Map("key1" -> StringValue("v1"),
                   "key2" -> MapValue(Map("sub" -> StringValue("val")))))

def allValues(s: ConfigValue): Iterable[String] = {
  s match {
    case StringValue(v) => Seq(v)
    case MapValue(map) => map.values.flatMap(v => allValues(v))
  }
}

println(allValues(struct))

По тому, как ваша структура похожа наJSON. Может быть, вы могли бы повторно использовать библиотеку JSON.

...