2

考虑我要解决的问题的简化版本。这是我当前的实现。

case class Foo()

def addFoo(json: String): EitherT[Future, Exception, Long] = {
  def parse(json: String): EitherT[Future, Exception, Foo] = ???

  def validate(foo: Foo): EitherT[Future, Exception, Foo] = ???

  def save(foo: Foo): EitherT[Future, Exception, Long] = ???

  for {
    foo <- parse(json)
    _ <- validate(foo)
    id <- save(foo)
  } yield id
}

这感觉不对,因为尽管validate返回了EitherTor ExceptionFoo但它只是执行验证并返回异常或未更改的foo值。所以,我们永远不会对正确的部分感兴趣,也Either永远不会使用它。有没有更好地对应“验证”语义的方法?

4

2 回答 2

2

您可以更改类型签名validate以添加更多类型安全性:

def validate(foo: Foo): EitherT[Future, Exception, ValidFoo]

ValidFoo看起来像这样:

object ValidFoo {
  def believeMeItsValid(raw: Foo): ValidFoo = new ValidFoo(raw)
}

class ValidFoo private (val foo: Foo)

并且save只接受经过验证的输入:

def save(foo: ValidFoo): EitherT[Future, Exception, Long]

这将迫使您在保存输入之前对其进行验证,并有助于防止布尔盲

于 2019-11-14T23:08:06.203 回答
1

如果您不关心正确的值,您可以使用Unit而不是Foo,例如:

def validate(foo: Foo): EitherT[Future, Exception, Unit] = ???
于 2019-11-14T20:41:50.630 回答