Play Framework [2.4.x] Twitter 示例。对发电机的这种特殊构造感到好奇

Play Framework [2.4.x] Twitter example. Curious as to this particular construct for a generator

使用此页面中的示例:

https://www.playframework.com/documentation/2.4.x/ScalaOAuth

然后我突然想到了这样的事情:

  def sessionTokenPair(implicit request: RequestHeader): Option[RequestToken] = {
    for {
      token <- request.session.get("token")
      secret <- request.session.get("secret")
    } yield {
      RequestToken(token, secret)
    }
  }

据我了解生成器(为了理解),第二个条目是基于第一个生成器的结果。

例如:secret <- request.session.get("secret") 可能来自 token <- request.session.get("token")

但很明显,当您查看结果时 RequestToken(token, secret) 情况并非如此。

How/why 这个构造是否优于简单地做:

RequestToken(request.session.get("token"), request.session.get("secret"))

啊 - 我想我可能会在问这个问题时自己回答这个问题(但它仍然没有解释两行的 "equalness?" 与通向下一行的一行......)

它的输出是 Option,因为它来自映射过程,而如果我们直接跳转到构造函数,我们将无法处理 None 情况。

如果 secrettoken 的生成器无关,那么谁能解释一下为什么这有效?

scala for-comprehension 是 flatMap 的语法糖。如果您使用 flatMap 代替,这就是上面的表达式:

request.session.get("token").flatMap { token =>
  request.session.get("secret").flatMap { secret =>
    Some(RequestToken(token, secret))
  }
}

-产生 Option[RequestToken].

此方法的要点是仅在定义了 secrettoken 时才生成 RequestToken。如果 两者都未定义 ,则结果为 None.

为了回答您的问题,for 理解中的第二个表达式仅基于第一个表达式的结果,如果第一个表达式产生 None,则不会调用第二个表达式 - 只是就像如果得到 token 产生 None.

则不会调用内部 flatMap

最后,我想更正您使用的一些术语。 for-comprehension 不是生成器。生成器可以与 for-comprehensions 一起使用,但那是因为它们是定义了 flatMapfilter 的单子。顺便说一句,任何定义了 flatMapfilter 的单子(例如 OptionFutureList 等)都可以与 for-comprehension 一起使用。

我喜欢将 <- 运算符视为 "let me take the value out of that wrapper (monad) for a second"。所以在 for comprehension 中,以下内容成立:

token = request.session.get("token") // this is an Option[Token]
token <- request.session.get("token") // this is a Token - we've taken it out of its wrapper

如果作品之一(return 和 Option

token <- request.session.get("token")
secret <- request.session.get("secret")

returns None,for comprehension 的结果也将是 None(可能不止两个产生式)。

换句话说,只有当所有这些return Some的东西,结果才会是Some.

的一个实例

Options 的情况下,它就像迭代具有零个或一个元素的列表的内容。

for comprehension 中第一个产生式的类型将决定整体结果的类型,在本例中为 Option,这与方法的 return 类型匹配 sessionTokenPair .

与简单 RequestToken(...) 的不同之处在于值被包装在 Option 中。这在 "no value" 和 "there is a value" 之间明显不同。否则你需要像 RequestToken 中的 isEmpty 方法,但这是通过使用 Option 来概括的(这是 Scala 中的首选方法)。

然后调用者可以"pattern match"结果。并且编译器将强制您以某种方式处理 Option.