如何在Scala中处理List的选项?

时间:2014-01-27 11:46:58

标签: scala functional-programming monads

假设我有一个函数getCustomersgetOrdersByCustomer

def getCustomer():List[Customer] = ...
def getOrdersByCustomer(cust: Customer): List[Order] = ...

现在我可以轻松定义一个函数getOrdersOfAllCustomers

def getOrdersOfAllCustomers(): List[Order] =
  for(cust <- getCustomer(); order <- getOrderByCustomer(cust)) yield order

到目前为止,非常好,但如果getCustomergetOrdersByCustomer返回列表的选项会怎样?

def getCustomer():Option[List[Customer]] = ...
def getOrdersByCustomer(cust: Customer): Option[List[Order]] = ...

现在我想实现两种不同的getOrdersOfAllCustomers()

  • 如果一个的函数返回None,则返回None;
  • 如果getCustomer返回“无”并且不关心getOrdersByCustomer是否返回“无”,则返回“无”。

你会如何建议实施它?

3 个答案:

答案 0 :(得分:3)

我认为您应该考虑三种可能性 - 填充列表,空列表或错误 - 并避免大量不合适的测试以确定发生了哪一种。

因此Try使用List

def getOrdersOfAllCustomers(): Try[List[Order]] = {
  Try(funtionReturningListOfOrders())
}

如果一切顺利,你会出现Success[List[Order]];如果没有,Failure[List[Order]]

这种方法的优点在于无论发生了什么 - 填充列表,空列表或错误 - 您可以使用列表完成所需的所有操作。这是因为Try就像Option一样是monad。继续filterforEachmap等等,直到您的内心,而不关心这三者中的哪一个发生。

一件事就是你必须弄清楚成功或失败是否发生时的尴尬时刻。然后使用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>更容易)