Scala for/yield 具有多个基于凭据的可选调用

Scala for/yield with multiple optional calls based on credentials

我需要一个完整的案例 class,与其他 3 个案例 class 一起构建,在一个电话中返回。但是,根据用户的凭据,他们可能会或可能不会访问该案例的某些部分 class。

以下是我目前的做法。(并且有效)它正在拨打电话,但之后会清除未经授权的案例 classes。如果他们没有适当的凭据和 return None,我理想情况下会停止通话(由于带宽低)。

持久实体服务调用需要一个 Option[PersonOne] 和 Option[PersonTwo],所以 .ask 必须 return 或者它说它是 returning 一个对象并且不会编译.

override def getPerson(id: UUID, credOne: Option[Boolean], credTwo: Option[Boolean]) = ServerServiceCall { _ =>
for {
  g <- registry.refFor[PersonEntity](id.toString()).ask(GetPersonGeneral)
  h <- registry.refFor[PersonEntity](id.toString()).ask(GetPersonOne) //if (credOne) **this 'if' does not work**

  s <- registry.refFor[PersonEntity](id.toString()).ask(GetPersonTwo)
} yield {
  val x: Option[PersonOne] = if (credOne == Some(true)) h else None
  val y: Option[PersonTwo] = if (credTwo == Some(true)) s else None
  CompletePerson(g.get, x, y)

  //TODO catch if no employee is returned
  //throw NotFound (s"Person not Found with $id");
}

}

我不太确定你在问什么,但你是否担心如果

registry.refFor[PersonEntity](id.toString()).ask(GetPersonGeneral)

returns None 您会继续拨打昂贵的 .ask 电话吗?因为这不会发生,正如我们可以从这里看到的

def giveMeSome = {println("giving you Some"); Some(1)}
def giveMeNone = {println("giving you None"); None}
def giveMeSomeMore = {println("giving you Some more"); Some(2)}

val ans = for {
  a <- giveMeSome
  f <- giveMeNone
  q <- giveMeSomeMore
} yield (a, f, q)

println(ans)

打印

giving you Some
giving you None
None

我们还可以看到,在这种情况下,您会得到 None 回复。我不知道你是想要 None 还是抛出错误。如果你想要一个错误,你可以把上面的包裹起来

我没有完全理解你的问题,但根据我的理解,你想先检查是否 credOne == Some(true) && credTwo == Some(true) 然后再继续 return None

override def getPerson(id: UUID, credOne: Option[Boolean], credTwo: Option[Boolean]) 
  =
   for {
       cone <- credOne
       ctwo <- credTwo
       if cone
       if ctwo
   } yield {
   ServerServiceCall { _ =>
     for {
         g <- registry.refFor[PersonEntity](id.toString()).ask(GetPersonGeneral)
         h <- registry.refFor[PersonEntity](id.toString()).ask(GetPersonOne)
         s <- registry.refFor[PersonEntity](id.toString()).ask(GetPersonTwo)
         if g.isDefined
         } yield {
           CompletePerson(g.get, h, s)
          }
       }

这是您函数的一个版本,如果适当的凭证值为 Some(true):

,它只会调用 ask
override def getPerson(id: UUID, credOne: Option[Boolean], credTwo: Option[Boolean]) = ServerServiceCall { _ =>
  CompletePerson(
    registry.refFor[PersonEntity](id.toString()).ask(GetPersonGeneral).get,
    credOne.filter(_ == true).flatMap(_ => registry.refFor[PersonEntity](id.toString()).ask(GetPersonOne)),
    credTwo.filter(_ == true).flatMap(_ => registry.refFor[PersonEntity](id.toString()).ask(GetPersonTwo))
  )
}

关键部分是这样的:

credX.filter(_ == true).flatMap(...)
  • 如果 credXNone 这将 return None
  • 如果 credX 包含 false 它将 return None
  • 如果 credXSome(true) 那么 flatMap 将调用 ask 函数
  • 如果askreturns None那么表达式会returnNone,否则会returnSome[PersonX]

我对某些数据类型有点不清楚,但我认为这应该让您对如何处理此代码有所了解。 (例如,裸 .get 看起来很危险,因为它可能会抛出异常)

评论后编辑

我解决了 filter(_) 的问题,它应该是 filter(_ == true)

看起来 ask 实际上 return 是 Option[Option[T]],在这种情况下,这可能更接近所需。

def getPerson(id: UUID, credOne: Option[Boolean], credTwo: Option[Boolean]) = ServerServiceCall { _ =>
  for {
    g <- registry.refFor[PersonEntity](id.toString()).ask(GetPersonGeneral)
    gen <- g
  } yield {
    val p1 = credOne.filter(_ == true).flatMap(_ => registry.refFor[PersonEntity](id.toString()).ask(GetPersonOne))).flatten
    val p2 = credTwo.filter(_ == true).flatMap(_ => registry.refFor[PersonEntity](id.toString()).ask(GetPersonTwo))).flatten

    CompletePerson(gen, p1, p2)
  }
}