简体   繁体   English

Scala Yeild 返回 Try[Either[]] 而不是 Either

[英]Scala Yeild returning Try[Either[]] rather then Either

I am trying to do some handson with scala basic operations and got stuck here in the following sample code我正在尝试对 scala 基本操作进行一些动手操作,并在以下示例代码中陷入困境

  def insuranceRateQuote(a: Int, tickets:Int) : Either[Exception, Double] = {
    // ... something
    Right(Double)
  }

  def parseInsuranceQuoteFromWebForm(age: String, numOfTickets: String)  : Either[Exception, Double]= {
    try{
      val a = Try(age.toInt)
      val tickets = Try(numOfTickets.toInt)

      for{
        aa <- a
        t <- tickets
      } yield insuranceRateQuote(aa,t)        // ERROR HERE
    } catch {
      case _ => Left(new Exception)}
  }

The Error I am getting is that it says found Try[Either[Exception,Double]]我得到的错误是它说found Try[Either[Exception,Double]]

I am not getting why it is wrapper under Try of Either我不明白为什么它是 Try of Either 下的包装器

PS - This must not be the perfect way to do in scala so feel free to post your sample code:) PS - 这一定不是在 scala 中做的完美方式,所以请随时发布您的示例代码:)

The key to understand is that for-comprehensions might transform what is inside the wrapper but will not change the wrapper itself.要理解的关键是,理解可能会改变包装器内部的内容,但不会改变包装器本身。 The reason is because for-comprehension de-sugar to map / flatMap calls on the wrapper determined in the first step of the chain.原因是因为对map / flatMap的理解脱糖调用链的第一步中确定的包装器。 For example consider the following snippet例如考虑以下代码片段

val result: Try[Int] = Try(41).map(v => v + 1)
// result: scala.util.Try[Int] = Success(42)

Note how we transformed the value inside the Try wrapper from 41 to 42 however the wrapper remained unchanged.请注意我们如何将Try包装器中的值从41转换为42 ,但包装器保持不变。 Alternatively we could express the same thing using a for-comprehension或者,我们可以使用 for-comprehension 来表达同样的事情

val result: Try[Int] = for { v <- Try(41) } yield v + 1
// result: scala.util.Try[Int] = Success(42)

Note how the effect is exactly the same.注意效果是如何完全相同的。 Now consider the following for comprehension which chains multiple steps现在考虑以下链接多个步骤的理解

val result: Try[Int] =
  for {
    a <- Try(41)   // first step determines the wrapper for all the other steps
    b <- Try(1)
  } yield a + b
// result: scala.util.Try[Int] = Success(42)

This expands to这扩展到

val result: Try[Int] =
  Try(41).flatMap { (a: Int) =>
    Try(1).map { (b: Int) => a + b }
  }
// result: scala.util.Try[Int] = Success(42)

where again we see the result is the same, namely, a value transformed inside the wrapper but wrapper remained untransformed.我们再次看到结果是相同的,即在包装器内部转换的值但包装器保持未转换。

Finally consider最后考虑

val result: Try[Either[Exception, Int]] =
  for {
    a <- Try(41)       // first step still determines the top-level wrapper
    b <- Try(1)
  } yield Right(a + b) // here we wrap inside `Either`
// result: scala.util.Try[Either[Exception,Int]] = Success(Right(42))

The principle remains the same - we did wrap a + b inside Either however this does not affect the top-level outer wrapper which is still Try .原理保持不变 - 我们确实将a + b包装在Either中,但这不会影响仍然是Try的顶级外部包装器。

Mario Galic's answer already explains the problem with your code, but I'd fix it differently. Mario Galic 的回答已经解释了您的代码的问题,但我会以不同的方式解决它。

Two points:两点:

  1. Either[Exception, A] (or rather, Either[Throwable, A] ) is kind of equivalent to Try[A] , with Left taking the role of Failure and Right the role of Success . Either[Exception, A] (或者更确切地说, Either[Throwable, A] )有点等价于Try[A]Left扮演Failure角色, Right扮演Success角色。

  2. The outer try / catch is not useful because the exceptions should be captured by working in Try .外部的try / catch没有用,因为异常应该通过在Try中工作来捕获。

So you probably want something like所以你可能想要类似的东西

def insuranceRateQuote(a: Int, tickets:Int) : Try[Double] = {
  // ... something
  Success(someDouble)
}

def parseInsuranceQuoteFromWebForm(age: String, numOfTickets: String):  Try[Double] = {
  val a = Try(age.toInt)
  val tickets = Try(numOfTickets.toInt)

  for{
    aa <- a
    t <- tickets
    q <- insuranceRateQuote(aa,t)
  } yield q
}

A bit unfortunately, this does a useless map(q => q) if you figure out what the comprehension does, so you can write it more directly as有点不幸的是,如果您弄清楚理解的作用,这会产生无用的map(q => q) ,因此您可以更直接地将其编写为

a.flatMap(aa => tickets.flatMap(t => insuranceRateQuote(aa,t)))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM