Scala 模式匹配之谜

Scala Pattern Matching Enigma

这是我对 Scala 中 99 个问题 (http://aperiodic.net/phil/scala/s-99/) 的第 3 个问题 (P03) 的尝试:

import scala.annotation._

// Find the nth element of a list.
// nth(2, List(1, 1, 2, 3, 5, 8)) = 2

object P03 {
  @tailrec def nth[A](n: Int, ls: List[A]): A = (n, ls) match {
    case (0, h :: t :: Nil) => h
    case (n, _ :: t)        => nth(n - 1, t)
    case _                  => println(n); throw new IllegalArgumentException
}

谜团是这段代码打印 -4 并抛出一个 IllegalArgumentException

解决办法当然是将第一种模式改成:

case (0, h :: _) => h

现在打印正确答案2

问题是为什么?两者之间的细微差别是什么:

case (0, h :: t :: Nil) => h

&

case (0, h :: _) => h

谢谢!

不同的是h :: t :: Nil只匹配有两个元素的列表(htNil是列表结束的标记(我我不是 100% 确定它是确切的命名法))而 h :: _ 匹配每个非空列表,即至少有一个元素的列表,如果你检查 :: class 你会看到:

final case class ::[B](private var hd: B, private[scala] var tl: List[B]) extends List[B]

它有一个头和一个尾,其中第一个是列表的第一个元素,第二个是其余的,匹配 h :: t :: Nil 意味着获取列表的第一个元素,而不是第一个元素tail 然后应该有一个 Nil,匹配 h :: _ 意味着得到 head 然后你不关心剩下的只要有一个 head.