假设我有一个具有两个可选字段的Toto类:
case class Toto(a : Option[Int], b: Option[Int])
还有一个带有一个可选Toto的Titi类:
case class Titi(c : Option[Toto])
我们创建类Titi的实例:
val test = Titi(Some(Toto(Some(1),Some(2))))
现在,我想通过假设Titi或b可以等于None来访问Toto的第二个字段,但这条语句是不可能的:
test.c.getOrElse("Something").b.getOrElse(0)
我该怎么做?
答案 0 :(得分:7)
您应该使用flatMap:
test.c.flatMap(_.b).getOrElse(0)
在层次结构中任何位置的情况下,将返回None
0。
如果您的对象层次结构更深入,并且属性返回Option
,则可以链接flatMap
:
test.c
.flatMap(_.b)
.flatMap(_.d)
//...etc
Scala还具有用于解开深度嵌套的monadic类型的特殊语法,称为for comprehension
:
val result = for {
c <- test.c
a <- c.a
} yield a
result.getOrElse(0)
在后台,它被编译为与链接的flatMap
类似的代码。
这基本上是这样的:
如果c
是None
,则直接进入getOrElse
并返回0
如果为Some
,则检查b
,如果为None,则转到getOrElse
,否则返回包装在Some
中的值。
如果您想返回不同的东西来区分哪个Option
为None,那么我只用match
:
test.c match {
case Some(c) => c.getOrElse(0)
// if you return String in one branch and integer in other then inferred type would be Any!
case None => "Something"
}
答案 1 :(得分:2)
您的Val测试是错误的,应该是这个
val test = Titi(Some(Toto(Some(1),Some(2))))
另一件事,在getOrElse中,您必须放置一个有意义的类型
test.c.getOrElse(Toto(None,None))
答案 2 :(得分:2)
您可以通过模式匹配来实现
val test: Titi = Titi(Some(Toto(Some(1), None)))
val res = test.c match {
case Some(Toto(_, Some(x))) => x
case _ => 0
}
结果:
0
答案 3 :(得分:-1)
val x = test match {
case Titi(x) => {
x match {
case Some(x) => {
x.b match {
case Some(z) => z
case None => 1
}
}
case None => 1
}
}
case _ => 1
} //> x : Int = 2
答案 4 :(得分:-1)
u可以使用折叠
test.c.fold(0)(_.b.fold(0)(i => i))