List 查找列表中的最后第二项,请解释此解决方案

List 查找列表中的最后第二项,请解释此解决方案,list,scala,recursion,functional-programming,pattern-matching,List,Scala,Recursion,Functional Programming,Pattern Matching,有人能逐行评论这是在做什么吗 [A]是不是像c#中那样的泛型?我们会这样做吗 h似乎没有定义 我认为算法的主要部分是递归调用: // But pattern matching also makes it easy. def penultimateRecursive[A](ls: List[A]): A = ls match { case h :: _ :: Nil => h case _ :: tail => penultimateRecursive(ta

有人能逐行评论这是在做什么吗

[A]是不是像c#中那样的泛型?我们会这样做吗

h似乎没有定义

我认为算法的主要部分是递归调用:

// 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
是一个类型变量,意味着该函数是为任何类型
A
定义的

h
由模式匹配绑定:第一个
案例
声明,如果正好有两个元素,则调用第一个
h
并返回它

似乎没有检查清单中的两项

有:
h:::\u::Nil
表示“一个元素
h
,后跟任何元素,后跟不再有元素。”
Nil
不是元素,它是列表的结尾

然后拿第一件去拿最后的第二件


在两个元素列表中取第一个元素意味着取倒数第二个元素。如果列表中的元素少于或多于两个,则其他两种情况适用。

理解模式匹配的关键是要认识到,
x::y
将只匹配一个列表,其中单个项
x
,然后是列表的其余部分
y
(可能只是
Nil
,也可能是多个元素),这意味着“这里需要一些东西,但我们不会麻烦给它命名”。(并且匹配按顺序出现,列表以
Nil
结尾)

您认为
[A]
是泛型类型是正确的

因此,第一行:

case _ :: tail     => penultimateRecursive(tail)
也就是说,如果我们的列表看起来(从概念上)像
Node(h)->Node(无论什么)->Nil
,那么我们返回
h
。这正是一个包含两个元素的列表,其中第一项已选中。请注意,
Nil
不匹配列表的任意尾部;它只匹配列表项的末尾
Nil
。这是因为Scala使用一条规则来区分这两个变量:小写变量被视为通配符,需要填入适当的值,而大写变量则被视为常数来匹配。(如果必须匹配小写名称,则可以使用反勾号将其环绕。)

好,现在假设它不是一个两元素列表。如果它不是空的,它将匹配

case h :: _ :: Nil => h
因此,如果我们没有两个元素的列表,我们就扔掉第一个元素,再试一次。最后,如果我们最终没有得到一个两元素列表,我们就可以

case _ :: tail => penultimateRecursive(tail)

我们完成了。(实际上,这也可能是
case Nil
,因为这是唯一与其他两个条目不匹配的可能性。)

第一行表示,如果h后面紧跟着另一个元素和Nil指针(在列表末尾),则将返回任何列表元素h。h后面的实际元素并不重要,这就是为什么使用u指定有一个元素,但不关心它的值

如果第一种情况不匹配,那么第二种情况将调用递归,前提是列表有一个head元素和至少一个tail元素


最后,在只包含一个元素的列表中退出。再一次,您不必关心元素值的实际值。

拉斯曼和雷克斯已经回答了您的问题,但有关“:”的更多详细信息,请参见第9章。

x::y
将匹配
x
,然后是任何列表
y
,即零个或更多元素。@larsmans-这就是我的意思,但是整个
Nil
是一个不明显的项目(或者,根据你的观点,不正确)。我将修正我的措辞。您可以更清楚地说明,模式匹配中的小写标识符类似于
val
声明,因为这些标识符是在该匹配的范围内创建的,并从匹配中提取赋值。请确定小写部分,并将其与比较的大写
Nil
。在语言引用中哪里可以找到运算符::?列表是抽象的,有两个子类:::“和Nil。以下是前者的文档:
case _ => throw new NoSuchElementException