6

我有这样的输入:"1 2 3 4 5".

我想做的是创建一组新变量,让a第一个成为序列,b第二个,xs其余作为序列(显然我可以在 3 个不同的行中完成,但我想使用多重赋值)。

一些搜索帮助我找到了正确的忽略序列模式,我可以使用它:

val Array(a, b, xs @ _*) = "1 2 3 4 5".split(" ")

我不明白的是,如果我用元组尝试它为什么不起作用?我收到一个错误:

val (a, b, xs @ _*) = "1 2 3 4 5".split(" ")

错误信息是:

<console>:1: error: illegal start of simple pattern

有没有不使用的多重分配的替代方案Array

几天前我刚开始玩 Scala,所以请多多包涵:-) 在此先感谢!

4

5 回答 5

18

其他答案告诉你为什么你不能使用元组,但数组对于这个目的很尴尬。我更喜欢列表:

val a :: b :: xs = "1 2 3 4 5".split(" ").toList
于 2012-04-24T18:02:19.167 回答
12

简单的答案

val Array(a, b, xs @ _*) = "1 2 3 4 5".split(" ")

您在此处看到的语法是简单的模式匹配。它之所以有效,是因为"1 2 3 4 5".split(" ")计算结果为Array

scala> "1 2 3 4 5".split(" ")
res0: Array[java.lang.String] = Array(1, 2, 3, 4, 5)

由于右手边是一个Array,左手尺寸上的图案也必须是Array

仅当右侧大小也计算为元组时,左侧才可以是元组:

val (a, b, xs) = (1, 2, Seq(3,4,5))

更复杂的答案

从技术上讲,这里发生的是模式匹配语法正在调用对象unapply上的方法Array,如下所示:

def unapplySeq[T](x: Array[T]): Option[IndexedSeq[T]] =
  if (x == null) None else Some(x.toIndexedSeq)

请注意,该方法接受一个Array. 这是 Scala 必须在作业的右侧看到的内容。它返回一个Seq,它允许@_*您使用的语法。

您的带有元组的版本不起作用,因为Tuple3'sunapplySeq是用 aProduct3作为其参数定义的,而不是 a Array

def unapply[T1, T2, T3](x: Product3[T1, T2, T3]): Option[Product3[T1, T2, T3]] =
  Some(x)

unapply实际上,您可以通过简单地创建一个对象并编写一个orunapplySeq方法来做任何您想做的事情。

于 2012-04-24T17:47:41.980 回答
7

答案是:

val a :: b :: c = "1 2 3 4 5".split(" ").toList

应该澄清的是,在某些情况下,可能只想绑定列表中的前 n 个元素,而忽略不匹配的元素。为此,只需添加一个尾随下划线:

val a :: b :: c :: _ = "1 2 3 4 5".split(" ").toList

那样:

c = "3" vs. c = List("3","4","5")
于 2012-04-24T18:02:53.747 回答
2

我无论如何都不是 Scala 方面的专家,但我认为这可能与 Scala 中的元组只是从 Tuple2 到 Tuple22 的类的语法糖有关。

意思是,Scala 中的元组不像 Python 或其他同类语言那样灵活的结构,因此它不能真正创建先验大小未知的元组。

于 2012-04-24T17:47:43.483 回答
1

我们可以使用模式匹配从字符串中提取值并将其分配给多个变量。不过,这需要两行。

Pattern 表示有 3 个数字([0-9]),中间有空格。在第三个数字之后,可以有也可以没有文字,我们不关心(.*)。

val pat = "([0-9]) ([0-9]) ([0-9]).*".r
val (a,b,c) = "1 2 3 4 5" match { case pat(a,b,c) => (a,b,c) }

输出

a: String = 1
b: String = 2
c: String = 3
于 2017-07-20T20:46:31.520 回答