未来[Scala中的[AppError,Option [User]]]

use*_*116 7 functional-programming scala

正如标题中所提到的,使用这种数据结构是否有意义?让我逐一解释:

  • 未来 - 表示异步计算
  • 要么 - 传达已知错误
  • 选项 - 表示可能不存在该值

看着这个我有点害怕.使用这种类型的组合是一个好习惯吗?

maa*_*asg 5

我们来看一下解决方案空间:

Success(Right(Some(user))) => Everythig OK, got an user
Success(Right(None)) => Everything OK, no user
Success(Left(AppError)) => Something went wrong at app level
Failure(Exception) => Something went wrong
Run Code Online (Sandbox Code Playgroud)

这看起来非常具有表现力,但是当你尝试用其他调用组合这样的嵌套结构时(参见转换阻塞代码到使用scala期货)作为一个组合的例子,事情变得很难看Future[Option[T]])

因此,遵循最小权力的原则,我们会问自己:是否存在保留语义的不太复杂的替代方案?有人可能会说,Future[User]如果我们充分利用异常(和异常层次结构)的潜力,那就足够了.

让我们检查:

Everythig OK, got an user => Success(user)
Everything OK, no user => Failure(UserNotFoundException)  (Application level exception)
Something went wrong at app level => Failure(AppException) (Application level exception)
Something went wrong => Failure(Exception) (System-level exception)
Run Code Online (Sandbox Code Playgroud)

此方法的唯一限制是API的用户需要了解异常,这在界面中不会自我记录.最重要的是,拥有基于Futures 的API 将允许具有其他Future基于API的表达性monadic组合.

  • @YuvalItzchakov当在应用程序级别被带回时,`Exception`s只是具有错误代表的类.:-)我同意ADT是不错的选择.我唯一的观点是开始简单并在需要时添加复杂性. (2认同)

Sar*_*ngh 2

Future[Either[AppError, Option[User]]]返回类型这样的事情在原型设计时可能没问题,但是一旦完成原型设计,您应该考虑提供更好的可读性和可表达性的选项。

\n\n

让我们以此Future[Either[AppError, Option[User]]]为例。假设有一个方法具有此返回类型。

\n\n
def fetchUser(userId: UUID): Future[Either[AppError, Option[User]]]\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在,您可以选择创建更具表现力的类型层次结构......例如,

\n\n
// Disclamer :\n//     this is just for pointing you out towards a direction and\n//     I am sure many can propose a better design hierarchy\n\ntrait Model\ncase class User(id: UUID,....) extends Model\n\n// Fetch Result protocol\n\nsealed trait FetchModelResult\n\ncase class FetchModelSuccess(model: Model) extends FetchModelResult\n\nsealed trait FetchModelFailure extends FetchModelResult\n\ncase class ModelNotFound extends FetchModelFailure\n...\ncase class FetchModelGenericFailure(ex: Exception) extends FetchModelFailure\n\n// App Result protocol\n\nsealed trait AppResult\n\ncase class AppResultSuccess[T](result: T) extends AppResult\n\nsealed trait AppResultFailure extends AppResult\n\ncase class AppResultGenericFailure(ex: Exception) extends AppResultFailure\n\n// fetch user problem\n\ndef fetchUser(userId: UUID): Future[FetchModelResult] = ???\n\n// Notice that we are not using the generic AppError here\n// This is called segregation of problems\n// the current problem is fetching the user\n// so our design is just to represent what can happen while fetching\n// Now whichever method is using this can come-up with an AppError\n// or AppResult based on what is gets from here.\n\ndef fetchUserApiHandler(userId: UUID): Future[AppResult] =\n  fetchUser(userId).map({\n    case FetchModelSuccess(model) => .....\n    case FetchModelFailure(ex) => ....\n  })    \n
Run Code Online (Sandbox Code Playgroud)\n\n

另一种选择是使用 或 的一元组合和转换实用scalaz程序cats

\n\n

Ra\xc3\xbal Raja Mart\xc3\xadnez 在他的一次演讲中解决了类似的问题,并提出了一些解决这些问题的方法 -团队对 Scala FP 新兴模式的旅程 - Run Wild Run Free

\n