Журнал предупреждений в сопоставлении с образцом без возврата Any - PullRequest
1 голос
/ 03 марта 2020

У меня есть итерация массивов, которые я пытаюсь превратить в классы дел, и я сопоставляю их для этого. Если массив не может быть преобразован в класс case, я хочу записать предупреждение и продолжить сопоставление. Однако, когда я реализую предупреждение, тип возвращаемого значения меняется с Iterable[MyCaseClass] на Iterable[Any], что не то, что я хочу. Например:

case class MyCaseClass(s1: String, s2: String)
object MyCaseClass {
  def apply(sa: Array[String]) = new MyCaseClass(sa(0), sa(1))
}

val arrayIterable: Iterable[Array[String]] = Iterable(Array("a", "b"), Array("a", "b", "c"))

def badReturnType(): Iterable[Any] = { // Iterable[Any] is undesireable
  arrayIterable map {
    case sa: Array[String] if sa.length == 2 => MyCaseClass(sa)
    case _ => println("something bad happened!") // but warnings are good
  }
}

def desiredReturnType(): Iterable[MyCaseClass] = { // Iterable[MyCaseClass] is desireable
  arrayIterable map {
    case sa: Array[String] if sa.length == 2 => MyCaseClass(sa)
    // but no warnings if things go wrong!
  }
}

Я хочу написать функцию, которая удовлетворяет следующим критериям:

  1. сопоставляет через Iterable, преобразовывая каждый элемент в MyCaseClass
  2. регистрировать предупреждения, когда я получаю массив, который не может быть преобразован в MyCaseClass
  3. после регистрации предупреждения, массив, переданный в критерии соответствия, игнорируется / отбрасывается
  4. тип возвращаемого значения должен быть Iterable[MyCaseClass].

Как мне выполнить эти условия?

Ответы [ 2 ]

5 голосов
/ 03 марта 2020

Попробуйте использовать List вместо Array и попробуйте обернуть в Option в сочетании с flatMap

l flatMap {
  case e if e.length == 2 => Some(MyCaseClass(e))
  case e => println(s"$e is wrong length"); None
}

Другой подход - partitionMap

val (lefts, rights) = l.partitionMap {
  case e if e.size == 2 => Right(MyCaseClass(e))
  case e  => Left(s"$e is wrong length")
}

lefts.foreach(println)
rights
3 голосов
/ 03 марта 2020

Вы можете сделать что-то вроде этого:

final case class MyCaseClass(s1: String, s2: String)

def parse(input: Array[String]): Either[String, MyCaseClass] = input match  {
  case Array(s1, s2) => Right(MyCaseClass(s1, s2))
  case _ => Left(s"Bad input: ${input.mkString("[", ", ", "]")}")
}

def logErrors(validated: Either[String, _]): Unit = validated match {
  case Left(error) => println(error)
  case Right(_)    => ()
}

def validateData(data: IterableOnce[Array[String]]): List[MyCaseClass] =
  data
    .iterator
    .map(parse)
    .tapEach(logErrors)
    .collect {
      case Right(value) => value
    }.toList

Что вы можете использовать так:

val arrayIterable = Iterable(Array("a", "b"), Array("a", "b", "c"))
validateData(arrayIterable)
// Bad input: [a, b, c]
// res14: List[MyCaseClass] = List(MyCaseClass("a", "b"))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...