21

メソッド呼び出しによって返された Option を、必要に応じて Failure 値を指定して Try に変換するには\/どうすればよいでしょうか?

たとえば、私は次のコードを持っています。

import scala.util._

case class ARef(value: String)
case class BRef(value: String)
case class A(ref: ARef, bRef: BRef)
class MismatchException(msg: String) extends RuntimeException(msg)

trait MyTry {

  // Given:
  val validBRefs: List[BRef]

  // Want to go from an Option[A] (obtained, eg., via a function call passing a provided ARef)
  // to a Try[BRef], where the b-ref needs to be checked against the above list of BRefs or fail:

  def getValidBRefForReferencedA(aRef: ARef): Try[BRef] = {

    val abRef = for {
      a <- get[A](aRef) // Some function that returns an Option[A]
      abRef = a.bRef
      _ <- validBRefs.find(_ == abRef)
    } yield (abRef)

    abRef match {
      case Some(bRef) => Success(bRef)
      case None => Failure(new MismatchException("No B found matching A's B-ref"))
    }
  }
}

最終的な一致をマップまたは flatMap または同様の構造にモーフィングし、理解のために前に組み込む方法が必要なように感じます。

また、BRef チェックの失敗と比較して、ARef から Option[A] を返す呼び出しが失敗した (None が返された) 場合に、別の失敗メッセージを指定できるようにしたいと思います (失敗の 1 つの理由を知ることだけに関心があります。そのため、scalaz Validation は理想的には適合しないように感じます)。

これはモナド変換子を使用するのに適した場所ですか? もしそうなら、scalaz は適切なものを提供していますか? あるいは、誰かがそれがどのように見えるかの例を挙げてもらえますか?

4

7 に答える 7

8

for-comp を使用して最初から a で開始するとTry、最後に一致を排除できます。OptionTryビアに強制することでこれを行うことができますfold。これは次のようになります。

def getValidBRefForReferencedA(aRef: ARef): Try[BRef] = {
  for {
    a <- get[A](aRef).fold[Try[A]](Failure[A](new OtherException("Invalid aRef supplied")))(Success(_))
    abRef = a.bRef
    _ <- validBRefs.find(_ == abRef).fold[Try[BRef]](Failure(new MismatchException("No B found matching A's B-ref")))(Success(_))
  } yield abRef
}

このアプローチでは、2 つの異なるチェックに対して異なる例外を取得できます。完璧ではありませんが、おそらくうまくいくでしょう。

于 2013-07-08T12:10:00.480 に答える
2

を使用する場合はEither、次を使用できますOption.toRight

def getValidBRefForReferencedA(aRef: ARef): Either[Throwable,BRef] = {    
  for {
    a <- get[A](aRef).toRight[Throwable](new Exception("Invalid ARef")).right
    bRef <- validBRefs.find(_ == a.bRef).toRight(new MismatchException("No B found matching A's B-ref")).right
  } yield bRef
}

を使用するTryと、必要に応じて適切な例外をスローし、全体を Try.apply(例外をキャッチしてFailureインスタンスとして提示する) でラップすることにより、非常に手続き的な方法でコードを簡単に記述できます。

def getValidBRefForReferencedA(aRef: ARef): Try[BRef] = Try {
  val a = get[A](aRef).getOrElse(throw new Exception("Invalid ARef"))
  validBRefs.find(_ == a.bRef).getOrElse(throw new MismatchException("No B found matching A's B-ref"))
}
于 2013-07-08T09:22:36.367 に答える
1

[さまざまな障害を特定するために編集]

単純化してみた

def getValidBRefForReferencedA(aRef: ARef): Try[BRef] = {
  val abRef = for {
    a <- get[A](aRef)
    bRef = a.bRef
    result = Either.cond(validBRefs.contains(bRef), bRef, "Invalid B Reference")
  } yield result

  abRef.map {
    case Right(bRef) => Success(bRef)
    case Left(error) => Failure(new InvalidReferenceException(error))
  }.getOrElse(Failure(new MismatchException("No B found matching A's B-ref")))
}
于 2013-07-08T09:31:44.533 に答える