// But pattern matching also makes it easy.
def penultimateRecursive[A](ls: List[A]): A = ls match {
case h :: _ :: Nil => h
case _ :: tail => penultimateRecursive(tail)
case _ => throw new NoSuchElementException
}
有人可以逐行评论这是做什么的吗?
[A]是否像c#一样通用,我们会这样做吗?
h似乎没有被定义?
我认为算法的主要部分是递归调用:
case _ :: tail => penultimateRecursive(tail)
似乎没有检查列表中的2个项目,然后拿第1个项目获得第2个项目,很困惑!
答案 0 :(得分:10)
理解模式匹配的关键是要意识到x :: y
将仅匹配列表,其中包含单个项x
,后跟列表的其余部分{{1 (可能只是y
,或者可能是很多元素),Nil
表示“这里需要有东西,但我们不会打扰它”。 (并且匹配按顺序发生,并且列出以_
结尾。)
你是正确的Nil
是通用类型。
所以,第一行:
[A]
说,如果我们的列表看起来像(概念上)case h :: _ :: Nil => h
,那么我们返回Node(h) -> Node(whatever) -> Nil
。这正是一个包含所选第一个项目的双元素列表。请注意,h
不匹配列表的任意尾部;它仅匹配列表末尾项Nil
。这是因为Scala用来区分这两者的规则:小写变量被视为要填充适当值的通配符,而大写变量被视为要匹配的常量。 (如果必须匹配小写名称,则可以通过反引号将其包围。)
好的,现在假设它不是一个双元素列表。然后,如果它不是空的,它将匹配
Nil
所以如果我们没有两个元素的列表,我们会扔掉第一个项目并再试一次。最后,如果我们以某种方式永远不会得到一个双元素列表,我们就会进入
case _ :: tail => penultimateRecursive(tail)
我们已经完成了。 (实际上,这也可能是case _ => throw new NoSuchElementException
,因为这是唯一与其他两个条目不匹配的可能性。)
答案 1 :(得分:4)
A
是一个类型变量,意味着该函数通常为任何类型A
定义。
h
受模式匹配约束:第一个case
个状态,如果只有两个元素,则调用第一个h
并返回它。
似乎没有检查列表中的2个项目
有:h :: _ :: Nil
表示“元素h
,后跟任何元素,后面没有更多元素。” Nil
不是元素,它是列表的末尾。
然后拿第一项获得第二名
取两个元素列表中的第一个 意味着取倒数第二个。如果列表中的元素少于或少于两个,则另外两种情况适用。
答案 2 :(得分:3)
larsmans和Rex已经涵盖了您的问题,但有关'::'http://www.scala-lang.org/docu/files/ScalaByExample.pdf
的详细信息,请参阅第9章。答案 3 :(得分:1)
第一行表示如果h后跟另一个和Nil指针(在列表的末尾),则将返回任何列表元素h。 h后面的实际元素并不重要,这就是为什么你使用_来指定有一个元素,但你不关心它的值。
如果第一种情况不匹配,如果列表具有头元素和至少一个元素的尾部,则第二种情况将调用递归。
最后,你在只包含一个元素的列表上拯救。再一次,您不必关心元素值的实际值。