如何使用Option monad?我正在浏览scala api并且有一个例子(我的意思是第二个),
由于理解的工作原理,如果从request.getParameter返回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(""))
我收到编译错误。这应该如何运作?
答案 0 :(得分:13)
由于此原因,您收到编译器错误
name <- None
这样,None
的类型设置为None.type
,变量name
被推断为类型Nothing
。 (也就是说,如果它实际存在,它会有这种类型,但很明显,for comprehension甚至不能在运行时创建它。)因此,没有方法name.trim
存在且不会编译。
如果您有request.getParameter("name")
可用,则其类型为Option[String]
,name
可能会有String
类型,name.trim
会被编译。
您可以通过指定None
:
name <- None: Option[String]
答案 1 :(得分: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
来明确地避免混乱(例如额外的变量名称)表达式的语义内容。
答案 2 :(得分:3)
要扩展Debilski的答案,您也不需要在Some()
中明确包装后续值,您实际映射的唯一值是原始name
。
更好的方法是直接使用map
和filter
操作,而不是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("") )