более читаемый шаблон scala для сопоставления успеха

Я считаю, что кейс Success часто погребен под совпадением множества ошибок и одного успеха. Есть ли другой способ написать это более четко, чтобы успех выделялся, возможно, наличием всех ошибок в частичной функции? Или, возможно, есть другой способ написать это, но более чисто. В общем, я просто ищу другие идеи/решения, которые можно было бы реализовать.

results.responseCode match {
  case Success =>
    // TODO make this less smelly. can results.results be None?
    val searchResults = results.results.get.results
    SomeService.getUsersFromThriftResults(
      userRepo,
      searchResults,
      Seq(WithCounts)) map { userResults =>
      val renderableStatuses = getStatuses(searchResults, userResults.userMap)
      new JsonAction(transformedQuery, renderableStatuses)
    }
  case ErrorInvalidQuery =>
    throw new SomeBadRequestException("invalid query")
  case ErrorOverCapacity |
       ErrorTimeout =>
    throw new SomeServiceUnavailableException("service unavailable")
  //TODO: take care of these errors differently
  //          case ErrorInvalidWorkflow |
  //               ErrorBackendFailure |
  //               ErrorEventNotFound |
  //               PartialSuccess |
  case _ =>
    throw new SomeApplicationException("internal server error")
}

person Dean Hiller    schedule 20.08.2014    source источник
comment
Я не понимаю, почему плоская версия уже не совсем хороша и проста.   -  person Erik Kaplun    schedule 20.08.2014


Ответы (4)


Вы можете связать частичные функции с orElse.

Что-то вроде

type ResponseCode = Int // This would be the type of the results.responseCode.
type RespHandler = PartialFunction[ResponseCode, JsonAction]

val invalidQuery: RespHandler =
  { case ErrorInvalidQuery => ... }

val overCapacity: RespHandler =
  { case ErrorOverCapacity => ... }

results.responseCode match {
  case Success => ...
} orElse invalidQuery orElse overCapacity orElse ...

Вы можете узнать больше об этом в этой записи блога: Объединение частичных функций с orElse

Изменить: это не работает так, как написано, вам нужно составить обработку, а затем apply (например, (success orElse invalidQuery ..)(results.getResponseCode)).

Лучшее решение — изменить его так, чтобы он возвращал Try[ResponseCode] и обрабатывал исключение в блоке соответствия Failure.

person Daenyth    schedule 20.08.2014
comment
Если вы можете изменить API, вы все равно должны использовать вместо него Try или аналогичный. - person Daenyth; 20.08.2014
comment
Это не правильно. Блок case для совпадения не является PF, хотя и выглядит таковым. Я думаю, никто не ввел это в REPL? Это правда, что вы можете связать PF как (a orElse b)(x). - person som-snytt; 20.08.2014
comment
SO нужна функция, в которой должны запускаться фрагменты кода; или вы можете указать, что фрагмент должен быть проверен; возможно, ОП мог запрашивать только проверенные фрагменты. - person som-snytt; 20.08.2014
comment
Вы правы, это не работает. Я видел это для catch и решил, что вы можете сделать то же самое с матчем. - person Daenyth; 20.08.2014

Вы можете попробовать Try[A].

Пример из документации:

import scala.util.{Try, Success, Failure}

def divide: Try[Int] = {
  val dividend = Try(Console.readLine("Enter an Int that you'd like to divide:\n").toInt)
  val divisor = Try(Console.readLine("Enter an Int that you'd like to divide by:\n").toInt)
  val problem = dividend.flatMap(x => divisor.map(y => x/y))
  problem match {
    case Success(v) =>
      println("Result of " + dividend.get + "/"+ divisor.get +" is: " + v)
      Success(v)
    case Failure(e) =>
      println("You must've divided by zero or entered something that's not an Int. Try again!")
      println("Info from the exception: " + e.getMessage)
      divide
  }
}
person monnef    schedule 20.08.2014

Вам следует рассмотреть возможность использования Both[Throwable, A] для представления типа результата.

http://tersesystems.com/2012/12/27/обработкаошибок-в-скале/

person Johnny Everson    schedule 20.08.2014

Вы можете преобразовать результат в Either[ResponseCode, Content]

def codeToEither(result: Result): Either[ResponseCode, Content] = 
  result.responseCode match {
    case Success => Right(result.results.get.results)
    case _       => Left(result.responseCode)
  }

А потом fold над ним

codeToEither(result).fold(
  errorCode => ... ,
  content   => ...
)

Или преобразуйте результат в Either[Exception, Content] таким же образом, если хотите.

person lambdas    schedule 20.08.2014
comment
Библиотека net.databinder.dispatch предоставляет интерфейс, с помощью которого вы можете получить объект Both. - person Daenyth; 20.08.2014