5

Option monad 是如何工作的?我正在浏览scala api并且有一个示例(我的意思是第二个),

由于 for comprehension 的工作原理,如果从 request.getParameter 返回 None,则整个表达式的结果为 None

但是当我尝试这段代码时:

 val upper = for {
   name <- None //request.getParameter("name")
   trimmed <- Some(name.trim)
   upper <- Some(trimmed.toUpperCase) if trimmed.length != 0
 } yield upper
 println(upper.getOrElse(""))

我得到一个编译错误。这应该如何工作?

4

3 回答 3

13

因此,您会收到编译器错误

  name <- None

这样,类型的None设置为None.type并且变量name被推断为类型Nothing。(也就是说,如果它确实存在,它将具有这种类型,但显然 for 理解甚至无法在运行时创建它。)因此不name.trim存在任何方法并且它不会编译。

如果你有request.getParameter("name")可用的,它的类型将是Option[String]name可能有类型String并且name.trim会编译。

您可以通过指定以下类型来解决此问题None

  name <- None: Option[String]
于 2010-11-26T19:30:58.840 回答
5

要扩展凯文的答案,您可以避免Some()使用=运算符而不是<-运算符来包装值:

val upper = for {
   name <- None: Option[String] //request.getParameter("name")
   trimmed = name.trim
   upper = trimmed.toUpperCase if trimmed nonEmpty
} yield upper

for-comprehension 将编译为与 Kevin 的版本非常相似的东西,但我经常发现它使用起来更清晰,map并且filter明确地避免了混乱(例如额外的变量名),不会给表达式的语义内容添加任何内容。

于 2010-11-26T22:28:48.783 回答
3

要扩展 Debilski 的答案,您也不需要显式地将后续值包装在 中Some(),您实际映射的唯一值是原始值name

更好的方法是直接使用mapandfilter操作而不是 for-comprehension:

注意:在幕后,Scala 编译器无论如何都会将 for-comprehension 转换为 map/flatMap/filter 的组合,因此这种方法永远不会比 for-comprehension 效率低,而且可能更有效

def clean(x:Option[String]) = x map { _.trim.toUpperCase } filterNot { _.isEmpty }

val param = None : Option[String] // request.getParameter("name")
println( clean(param).getOrElse("") )
于 2010-11-26T19:48:43.997 回答