sva*_*ens 2 scala optional flatmap
我无疑是Scala的新手,我在许多Scala示例中遇到的语法糖问题.它通常会产生一个非常简洁的陈述,但老实说到目前为止(对我而言)有点难以理解.
因此,我希望将Option类(安全解除引用)的典型用法作为开始理解的好地方,例如,在我看到的特定示例中使用下划线.
我发现了一篇非常好的文章,展示了使用Option来避免null的情况.
https://medium.com/@sinisalouc/demystifying-the-monad-in-scala-cc716bb6f534#.fhrljf7nl
他描述了一个用途:
trait User {
val child: Option[User]
}
Run Code Online (Sandbox Code Playgroud)
顺便说一句,您也可以将这些函数编写为就地lambda函数,而不是先验地定义它们.然后代码变为:
val result = UserService.loadUser("mike")
.flatMap(user => user.child)
.flatMap(user => user.child)
Run Code Online (Sandbox Code Playgroud)
那看起来很棒!也许不像人们在groovy中那样简洁,但也不错.
所以我想我会尝试将它应用到我想要解决的案例中.
我有一种类型Person,其中a的存在Person是可选的,但如果我们有一个人,他的属性是有保证的.出于这个原因,没有使用的Option的内型Person类型本身.
的Person具有PID它的类型的Id.该Id类型包括两种String类型; Id-Type和Id-Value.
我使用Scala控制台测试以下内容:
class Id(val idCode : String, val idVal : String)
class Person(val pid : Id, val name : String)
val anId: Id = new Id("Passport_number", "12345")
val person: Person = new Person(anId, "Sean")
val operson : Option[Person] = Some(person)
Run Code Online (Sandbox Code Playgroud)
好.设置我的人和它的可选实例.
我从上面的链接文章中了解到,我可以使用flatMap获得Persons Id-Val; 像这样:
val result = operson.flatMap(person => Some(person.pid)).flatMap(pid => Some(pid.idVal)).getOrElse("NoValue")
Run Code Online (Sandbox Code Playgroud)
大!这样可行.如果我事实上没有人,我的结果是"NoValue".
我使用flatMap(而不是Map)因为,除非我误解(并且我的Map测试不正确)如果我使用Map我必须提供备用或默认Person实例.我不想这么做.
好的,所以,flatMap是要走的路.
但是,这真的不是一个非常简洁的陈述.如果我以更加时髦的风格写作,我想我可以做这样的事情:
val result = person?.pid.idVal
Run Code Online (Sandbox Code Playgroud)
哇,这有点好!
当然,Scala有能力提供至少与Groovy一样好的东西吗?
在上面的链接示例中,他能够使用我之前提到的一些语法糖使他的陈述更简洁.下划线:
甚至更简洁:
val result = UserService.loadUser("mike")
.flatMap(_.child)
.flatMap(_.child)
Run Code Online (Sandbox Code Playgroud)
因此,在这种情况下,下划线字符似乎允许您跳过指定类型(推断类型)并将其替换为下划线.
但是,当我用我的例子尝试同样的事情时:
val result = operson.flatMap(Some(_.pid)).flatMap(Some(_.idVal)).getOrElse("NoValue")
Run Code Online (Sandbox Code Playgroud)
斯卡拉抱怨道.
<console>:15: error: missing parameter type for expanded function ((x$2) => x$2.idVal)
val result = operson.flatMap(Some(_.pid)).flatMap(Some(_.idVal)).getOrElse("NoValue")
Run Code Online (Sandbox Code Playgroud)
有人可以帮助我吗?
我怎么会误解这个?是否有一种简短的方法来编写我上面冗长的陈述?flatMap是实现我追求目标的最佳方式吗?或者是否有更简洁和/或可读的方法来做到这一点?
提前致谢!
你为什么坚持使用flatMap?我只是用map你的例子代替:
val result = operson.map(_.pid).map(_.idVal).getOrElse("NoValue")
Run Code Online (Sandbox Code Playgroud)
甚至更短:
val result = operson.map(_.pid.idVal).getOrElse("NoValue")
Run Code Online (Sandbox Code Playgroud)
您应该只使用flatMap返回Options的函数.你pid和idVals不是Options,所以只需要映射它们.
你说
我有一个Person类型,其中Person的存在是可选的,但如果我们有一个人,他的属性是有保证的.因此,在Person类型本身中没有使用Option类型.
这是您的示例和User示例之间的本质区别.在该User示例中,User实例的存在及其child字段都是选项.这就是为什么,要获得一个child,你需要flatMap.但是,因为在您的示例中,只有a的存在Person无法保证,在您检索到之后Option[Person],您可以安全地映射到其任何字段.
可以想象flatMap为a map,然后是a flatten(因此得名).如果我映射到孩子:
val ouser = Some(new User())
val child: Option[Option[User]] = ouser.map(_.child)
Run Code Online (Sandbox Code Playgroud)
我最终会得到一个Option[Option[User]].我需要将其压缩到一个单一的Option水平,这就是我flatMap首先使用的原因.
如果您正在寻找最简洁的解决方案,请考虑以下事项:
val result = operson.fold("NoValue")(_.pid.idVal)
Run Code Online (Sandbox Code Playgroud)
虽然人们可能会发现它不清楚或令人困惑
| 归档时间: |
|
| 查看次数: |
891 次 |
| 最近记录: |