我想知道在 Scala 中,这两段代码之间有什么区别/偏好吗?
// common code
case class Person(maybeAddress: Option[Address])
case class Address(maybeZipCode: Option[String])
链式平面图:
maybePerson
.flatMap(person => person.maybeAddress)
.flatMap(address => address.maybeZipCode)
嵌套平面图:
maybePerson
.flatMap(person => person.maybeAddress.flatMap(address => address.maybeZipCode))
谢谢!
根据提供的示例,除了样式之外没有太大区别。
如果我们看一下 Option.flatmap 的 scaladoc
/** Returns the result of applying $f to this $option's value if * this $option is nonempty. * * This is equivalent to: * {{{ * option match { * case Some(x) => f(x) * case None => None * } * }}} */ @inline final def flatMap[B](f: A => Option[B]): Option[B] = if (isEmpty) None else f(this.get)
如果我们按照scaladoc中显示的模式匹配重写您问题的每个示例,则第一种情况将是
// from
maybePerson
.flatMap(person => person.maybeAddress)
.flatMap(address => address.maybeZipCode)
// to
maybePerson match {
case Some(person) => person.maybeAddress
case None => None
} match { // this match will always be applied
case Some(address) => address.maybeZipCode
case None => None
}
第二个是
// from
maybePerson
.flatMap(person =>
person.maybeAddress
.flatMap(address =>
address.maybeZipCode
)
)
// to
maybePerson match {
case Some(person) =>
// this match will be applied only if maybePerson is Some
person.maybeAddress match {
case Some(address) => address.maybeZipCode
case None => None
}
case None => None
}
正如我之前详细介绍的,在我们正在分析的示例中,除了样式之外没有太大区别。
也许在更复杂的场景中,您将拥有必须计算的值,其中一些值的处理成本可能很高,或者会产生副作用,如果出现问题,您应该回滚。
话虽如此,从我的角度来看,我更喜欢用于理解
for {
person <- maybePerson
address <- person.maybeAddress
zipCode <- address.maybeZipCode
} yield zipCode
这是一种更垂直的风格,避免嵌套代码块,除非您将匿名函数提取到像这样的变量中声明的方法或函数
def personToAddress(person: Person): Option[Address] =
person.maybeAddress
def addressToZipCode(address: Address): Option[String] =
address.maybeZipCode
// first case
maybePerson
.flatMap(mapToAddress)
.flatMap(mapToZipCode)
// second case
def addressToZipCode(address: Address) =
address.maybeZipCode
def personToZipCode(person: Person) =
person
.maybeAddress
.flatMap(addressToZipCode)
maybePerson
.flatMap(personToZipCode)