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
只匹配有两个元素的列表(h
和t
,Nil
是列表结束的标记(我我不是 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.
这是我对 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
只匹配有两个元素的列表(h
和t
,Nil
是列表结束的标记(我我不是 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.