假设我有一个函数getCustomers
和getOrdersByCustomer
。
def getCustomer():List[Customer] = ... def getOrdersByCustomer(cust: Customer): List[Order] = ...
现在我可以轻松定义一个函数getOrdersOfAllCustomers
def getOrdersOfAllCustomers(): List[Order] = for(cust <- getCustomer(); order <- getOrderByCustomer(cust)) yield order
到目前为止,非常好,但如果getCustomer
和getOrdersByCustomer
返回列表的选项会怎样?
def getCustomer():Option[List[Customer]] = ... def getOrdersByCustomer(cust: Customer): Option[List[Order]] = ...
现在我想实现两种不同的getOrdersOfAllCustomers()
:
getCustomer
返回“无”并且不关心getOrdersByCustomer
是否返回“无”,则返回“无”。你会如何建议实施它?
答案 0 :(得分:3)
我认为您应该考虑三种可能性 - 填充列表,空列表或错误 - 并避免大量不合适的测试以确定发生了哪一种。
因此Try
使用List
:
def getOrdersOfAllCustomers(): Try[List[Order]] = {
Try(funtionReturningListOfOrders())
}
如果一切顺利,你会出现Success[List[Order]]
;如果没有,Failure[List[Order]]
。
这种方法的优点在于无论发生了什么 - 填充列表,空列表或错误 - 您可以使用列表完成所需的所有操作。这是因为Try
就像Option
一样是monad。继续filter
,forEach
,map
等等,直到您的内心,而不关心这三者中的哪一个发生。
一件事就是你必须弄清楚成功或失败是否发生时的尴尬时刻。然后使用match
表达式:
getOrdersOfAllCustomers() match {
case Success(orders) => println(s"Awww...yeah!")
case Failure(ex) => println(s"Stupid Scala")
}
即使您不使用Try
,我也恳请您不要处理与填充列表不同的空列表。
答案 1 :(得分:2)
试试这个,
def getOrdersOfAllCustomers(): Option[List[Order]] =
for{
cust <- getCustomer().toList.flatten;
order <- getOrderByCustomer(cust).toList.flatten
} yield order
答案 2 :(得分:2)
这应该这样做:
def getOrdersOfAllCustomers(): Option[List[Order]] = {
getCustomer() flatMap { customers =>
//optOrders is a List[Option[List[Order]]]
val optOrders = customers map { getOrderByCustomer }
// Any result must be wrapped in an Option because we're flatMapping
// the return from the initial getCustomer call
if(optOrders contains None) None
else {
// map the nested Option[List[Order]]] into List[List[Order]]
// and flatten into a List[Order]
// This then gives a List[List[Order]] which can be flattened again
Some(optOrders.map(_.toList.flatten).flatten)
}
}
}
困难的部分是处理getOrderByCustomer
的一个嵌套调用返回None
并将结果冒泡回外部范围的情况(这就是为什么使用空列表所以< / em>更容易)