1

我想在这里理解这段代码

  def countChange(money: Int, coins: List[Int]): Int = (money, coins) match {
     case (0, _) => 1
     case (m, _) if m < 0 => 0
     case (_, cs)  if cs.isEmpty => 0
     case (m, cs) => countChange(m - cs.head, cs) + countChange(m, cs.tail) 
  }
}

我无法理解对(0,_),(m,_)和因为术语(_,cs)和在代码正文中未定义。(m,cs)mcs

这个遍历 List 的结构叫什么?一对一些匹配的模式?

4

3 回答 3

2

该列表正在递归遍历。这种结构称为模式匹配

您可以像这样阅读它:

如果元组(money, coins)是第一个值的元组,0则返回1忽略元组的第二个值

如果元组(money, coins)是具有低于第一个值的元组,0则返回 0 忽略元组的第二个值。

等等...

用于模式匹配以_表示我们不在乎那个参数是什么,它可以是任何东西

Scala 中的模式匹配由unapplyObjects 方法支持,请阅读有关提取器的更多信息。这意味着对于每个case方法,unapply都将使用元组(money, coins)作为参数调用该方法,如果确定它是匹配的,它将将各自的第一个值和第二个值传递给case子句。

例子:

该声明case (m, _) => ...将导致调用Tuple2.unapply((money, coins))

笔记

案例类已经unapply为我们定义了方法。这就是为什么您可以在“开箱即用”的模式匹配中使用它们。Tuple2是一个案例类。

于 2017-09-03T14:50:36.737 回答
2

这是一个模式匹配的例子,它被用来递归地遍历你的硬币列表。这是用注释重写的相同代码,重要的是要知道每个case语句都匹配元组的可能模式,并且_用于忽略元组的片段。

def countChange(money: Int, coins: List[Int]): Int = {

  // Construct a tuple for pattern matching on
  val tuple: (Int, List[Int])  = (money, coins)

  tuple match {

    // Check to see if money == 0
    case (0, _) => 1

    // m represents money, use a guard to check if m is negative 
    case (m, _) if m < 0 => 0

    // cs represents coins, use a guard statement check for empty list
    case (_, cs) if cs.isEmpty => 0

    // Recursive step.  Since the patterns are tried in order, we 
    // now know that if we make it to here m (money) is non-zero 
    // and non-negative, and we know that cs (coins) is a non-empty 
    // list.  Now we can  call the recursive function safely on 
    // the head of the list
    case (m, cs) => countChange(m - cs.head, cs) + countChange(m, cs.tail)
  }

}
于 2017-09-03T14:54:49.060 回答
1

这种结构通常用于同时匹配多个变量。在顶部match,您会看到(money, coins)。这意味着它在 和 的对匹配。它没有名字,因为它是完全普通的同时匹配两个值。moneycoins

我无法理解对(0,_),(m,_)和因为术语(_,cs)和在代码正文中未定义。(m,cs)mcs

这些术语在代码定义。cases 定义它们。这就是匹配和解构的全部意义所在。

(money, coins) match {
   case (0, _) => 1 // If money == 0, then coins is ignored and we return 1
   case (m, _) if m < 0 => 0 // m = money, coins is ignored. If m < 0, return 0
   case (_, cs)  if cs.isEmpty => 0 // money is ignored, cs = coins.
                                    // If we have no coins, return 0.
   case (m, cs) => countChange(m - cs.head, cs) + countChange(m, cs.tail)
   // Otherwise, m = money, cs = coins. Recurse down the list with
   // countChange(money - coins.head, coins) + countChange(money, coins.tail)
}

元组的原因(money, coins)是因为这些模式同时依赖 moneycoins。你要么需要嵌套matchs (丑陋的),要么做更丑陋的布尔逻辑来复制这些语义。

于 2017-09-03T14:58:41.837 回答