Необязательный параметр функции с универсальным типом возвращаемого значения - PullRequest
2 голосов
/ 13 июля 2010

Как бы вы реализовали класс, который анализирует некоторые входные данные с помощью регулярных выражений и преобразует основанную строку в какой-то другой тип? Мой подход:

class ARegex[T](regex:Regex, reform:Option[String => T]){
  def findFirst(input:String):Option[T] = {
    (regex.findFirstIn(input), reform) match{
      case (None, _) => None
      case (Some(s), None) => Some(s) // this won't compile because of type mismatch
      case (Some(s), Some(fun)) => Some(fun(s))
    }
  }
}

class BRegex[T](regex:Regex, reform:Option[String => T]) {
  def findFirst(input:String) = {  //returns Option[Any] - erasure
    (regex.findFirstIn(input), reform) match{
      case (None, _) => None
      case (Some(s), None) => Some(s)
      case (Some(s), Some(fun)) => Some(fun(s))
    }
  }
}

Ответы [ 3 ]

7 голосов
/ 13 июля 2010

Мы можем решить эту проблему, исключив часть Option типа reform и используя другой механизм, чтобы указать, что мы не хотим изменять соответствие каким-либо образом.Этот механизм должен использовать identity в качестве параметра по умолчанию или передавать идентификатор, когда вы не хотите, чтобы тип изменился.

class ARegex[T](regex:Regex, reform:String => T = identity[String](_)){
  def findFirst(input:String):Option[T] = {
    regex.findFirstIn(input) match{
      case None => None
      case Some(s) => Some(reform(s))
    }
  }
}

new ARegex("something".r).findFirst("something else") //returns Option[String]
new ARegex("3".r, {x=>x.toInt}).findFirst("number 3") //returns Option[Int]
2 голосов
/ 13 июля 2010

Ну, проблема в несоответствии типов, потому что вы возвращаете либо String, либо T, которые, конечно, объединены в Any.Вы не можете сказать, что собираетесь вернуть Option[T], а затем вернуть Option[String].

Кроме этого, упрощенная версия этого кода выглядит так:

class ARegex[T](regex: Regex, reform: Option[String => T]) {
  def findFirst(input: String): Option[Any] =
    regex findFirstIn input map { s => reform map (_(s)) getOrElse s }
}

Вы можетеверните Option[Either[String, T]], хотя.Код будет выглядеть так:

class ARegex[T](regex: Regex, reform: Option[String => T]) {
  def findFirst(input: String): Option[Either[String, T]] =
    regex findFirstIn input map { s => reform map (_(s)) toRight s }
}
1 голос
/ 13 июля 2010

Почему реформа Option [String => T] вместо просто String => T? Если вы не передадите механизм для создания экземпляра нужного вам типа, у системы во время выполнения не будет механизма для создания соответствующего объекта. Если вам действительно нужно передать Option [String => T], тогда ваш второй случай должен просто вернуть None.

Кроме того, flatMap - ваш друг, и он даст вам правильное поведение (т. Е. Если для реформы выбрано значение None, метод возвращает значение None.

class RegexExtractor[T](regex: Regex, reform: Option[String => T]) {
  def findFirst(input: String): Option[T] = reform.flatMap(f => regex.findFirstIn(input).map(f))
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...