Scala 列表的第二个元素

Scala 列表的第二个元素,scala,list,Scala,List,从《Scala编程》一书中,我得到了以下代码行: val second: List[ Int] => Int = { case x :: y :: _ => y } //warning: match may not be exhaustive. 它声明,如果整数列表不是空的或为零,则此函数将返回整数列表的第二个元素。这部分对我来说还是有点尴尬: case x :: y :: _ 这究竟是怎么回事?这是否对任何至少包含2个元素的列表进行数学运算,然后返回第二个元素?如果是的话,还

从《Scala编程》一书中,我得到了以下代码行:

val second: List[ Int] => Int = { case x :: y :: _ => y }
//warning: match may not be exhaustive.
它声明,如果整数列表不是空的或为零,则此函数将返回整数列表的第二个元素。这部分对我来说还是有点尴尬:

case x :: y :: _ 
这究竟是怎么回事?这是否对任何至少包含2个元素的列表进行数学运算,然后返回第二个元素?如果是的话,还有人能解释一下语法吗?我知道::是在正确的操作数上调用的。所以它可以写成

(_.::(y)).::(X)
我还是不明白为什么会返回2

val second: List[ Int] => Int = { case x :: y :: _ => y }
var x = List(1,2)
second(x) //returns 2 

second
是函数类型,它接受
List[Int]
并返回
Int

如果列表中有第一个元素(“x”)和第二个元素(“y”),那么无论接下来发生什么(我们不关心它),我们只返回元素“y”(这是列表中的第二个元素)

在任何其他情况下,都不会定义该函数。您可以检查:

scala> val second: PartialFunction[List[Int], Int] = {
     |     case x :: y :: _ => y
     |   }
second: PartialFunction[List[Int],Int] = <function1>

scala> second.isDefinedAt(List(1,2,3))
res18: Boolean = true

scala> second.isDefinedAt(List(1,2))
res19: Boolean = true

scala> second.isDefinedAt(List(0))
res20: Boolean = false
scala>val second:PartialFunction[List[Int],Int]={
|案例x::y::=>y
|   }
第二:部分函数[List[Int],Int]=
scala>second.isDefinedAt(列表(1,2,3))
res18:布尔值=真
scala>second.isDefinedAt(列表(1,2))
res19:布尔值=真
scala>second.isDefinedAt(列表(0))
res20:布尔值=假

在REPL中,您可以键入:

scala> val list = "a" :: "b" :: Nil 
list: List[String] = List(a, b)
它是从右到左读取的,意思是取一个列表的结尾(Nil),前置字符串“b”,然后到这个列表(“b”::Nil)前置字符串a,a:(“b”::Nil),但是你不需要paren,所以它可以写为“a”::“b”::Nil”

在模式匹配中,您将更经常看到:

... list match {
  case Nil => // ... 
  case x :: xs => // ...
}
要区分空列表和非空列表,其中xs可能是列表的其余部分,但也匹配Nil,例如,如果整个列表是(“b”::Nil),则x=“b”和xs=Nil

但是如果list=“a”::“b”::Nil,那么x=“a”和xs=(b::Nil)


在您的示例中,解构只是多了一步,而不是像xs这样的名称,而是使用了小丑符号uu,表示该名称可能没有使用,也没有发挥作用。

首先。当您考虑模式匹配时,您应该考虑匹配结构

case
语句的第一部分描述了一个结构。此结构可能描述一个或多个对推导结果有用的事物(变量)

在您的示例中,您感兴趣的是派生列表的第二个元素。在Scala中构建列表的简写方法是使用
方法(也称为cons)
也可用于描述
case
语句中的结构此时,您不应该在
案例的第一部分中考虑对
方法的评估。也许这就是为什么你要说
。::(y)。:(x)
::
cons操作符帮助我们描述列表的元素结构。在这种情况下,第一个元素(
x
),第二个元素(
y
)和它的其余部分(
通配符)。我们感兴趣的是一个结构,它是一个至少有2个元素的列表,第三个元素可以是任何东西-一个Nil表示列表的结尾或另一个元素-因此是通配符

case语句的第二部分使用第二个元素派生结果(
y

更多关于列表和考虑的信息

Scala中的列表类似于
链接列表
。您知道名为
head
的第一个元素以及列表其余部分的开头。当遍历链接列表时,如果列表的其余部分为
Nil
,则停止。这个
::
cons操作符帮助我们可视化链表的结构。尽管Scala compile实际上会调用
::
方法,如您所述从右到左求值
。::(x)

顺便说一句,您可能已经注意到Scala编译器可能会抱怨您的匹配不够详尽。这意味着这个
second
方法将适用于任何大小的列表。因为没有任何
case
语句来描述包含零或一个元素的列表。此外,如前面答案的注释所述,如果您对第一个元素不感兴趣,可以将其描述为通配符

case\uuu::y::\u=>y


我希望这有帮助

如果您在scala its的
head::tail
中看到列表的结构,则第一个元素被视为head,其余所有元素都被视为tail(Nil将是tail的最后一个元素)。每当执行x::y::\时,x将匹配列表的开头,剩余的将是尾部,y将再次匹配下一个列表的开头(第一个列表的尾部)

例如:

您可以通过不同的方式查看此列表:

1::2::3::4::5::Nil
1::List(2,3,4,5)
1::2::List(2,3,4,5)
等等


因此,尝试匹配模式。在您的问题中,y将给出第二个元素

x
可能是
\u
@Jubobs,这是正确的。除了下面的答案之外,我建议您阅读以下内容:它涉及提取器/未应用,以及它们与模式匹配的关系。它有点过时,但仍然是正确的,真的很好的解释!感谢您花时间以如此简洁的方式写下这篇文章。谢谢@Hansherrich
1::2::3::4::5::Nil
1::List(2,3,4,5)
1::2::List(2,3,4,5)