`:_*`(冒号下划线星号)在 Scala 中有啥作用?
Posted
技术标签:
【中文标题】`:_*`(冒号下划线星号)在 Scala 中有啥作用?【英文标题】:What does `:_*` (colon underscore star) do in Scala?`:_*`(冒号下划线星号)在 Scala 中有什么作用? 【发布时间】:2011-08-28 10:07:28 【问题描述】:我有以下来自this question 的代码:
def addChild(n: Node, newChild: Node) = n match
case Elem(prefix, label, attribs, scope, child @ _*) => Elem(prefix, label, attribs, scope, child ++ newChild : _*)
case _ => error("Can only add children to elements!")
里面的一切都很清楚,除了这个:child ++ newChild : _*
它有什么作用?
我知道Seq[Node]
与另一个Node
连接在一起,然后呢? : _*
是做什么的?
【问题讨论】:
非常感谢您在标题中添加(冒号下划线星号)! 【参考方案1】:它“splats”1 序列。
查看构造函数签名
new Elem(prefix: String, label: String, attributes: MetaData, scope: NamespaceBinding,
child: Node*)
被称为
new Elem(prefix, label, attributes, scope,
child1, child2, ... childN)
但这里只有一个序列,而不是child1
、child2
等,所以这允许将结果序列用作构造函数的输入。
1 这在 SLS 中没有可爱的名字,但这里有详细信息。重要的是它改变了 Scala 将参数绑定到具有重复参数的方法的方式(如上面的 Node*
所示)。
_*
类型注解在 SLS 的“4.6.2 重复参数”中有介绍。
参数部分的最后一个值参数可以用“*”作为后缀,例如(..., x:T )。那么方法内部这种重复参数的类型是 序列类型 scala.Seq[T]。具有重复参数的方法 T * take 可变数量的类型 T 参数。也就是说,如果一个方法 m 的类型为 (p1 : T1, . . . , pn : Tn,ps : S)U 应用于 k >= n 的参数 (e1, . . . , ek),然后 m 在该应用程序中具有类型 (p1 : T1, ... . . , pn : Tn,ps : S, . . . , ps0S)U, 有 k ¡ n 个类型 S 的出现,其中 ps 之外的任何参数名称都是 新鲜的。 这个规则的唯一例外是如果最后一个参数被标记为 通过 _ 类型注释的序列参数。如果将上面的 m 应用于参数 (e1, . . . , en,e0 : _),则该应用程序中 m 的类型被认为是 (p1 : T1, ... , pn : Tn,ps :scala.Seq[S])**
【讨论】:
我们喜欢称它为“Smooch 运营商”,尽管它实际上并不是运营商 :) 在 Python 中这称为解包 序列的长度是否有限制,比如Java varargs有限制?【参考方案2】:child ++ newChild
- 序列
:
- 类型归属,帮助编译器理解的提示,该表达式有什么类型
_*
- 接受任何值的占位符 + 可变参数运算符
child ++ newChild : _*
将Seq[Node]
扩展为Node*
(告诉编译器我们宁愿使用可变参数,而不是序列)。对于只能接受可变参数的方法特别有用。
【讨论】:
你能写更多关于“类型归属”的内容吗?它是什么以及它是如何工作的? ***.com/questions/2087250/… 很好的答案。因此,通过编写a: _*
,您是在告诉编译器将a
视为_*
的一个实例,在这种情况下只是Node*
【参考方案3】:
以上所有答案看起来都很棒,但只需要一个示例来解释这一点。 这里是:
val x : Seq[Seq[Int]] = Seq(Seq(1),Seq(2))
def f(arg: Seq[Any]*) : Int =
arg.length
f(x) //1 as x is taken as single arg
f(x:_*) // 2 as x is "unpacked" as a Seq[Any]*
所以现在我们知道:_*
的作用是告诉编译器:请解压缩此参数并将这些元素绑定到函数调用中的可变参数,而不是将 x 作为单个参数。
所以简而言之,:_*
是在将参数传递给可变参数时消除歧义。
【讨论】:
这是我一直在寻找的答案。其他的都很棒,但是这个简单的例子让我很开心。向@Keith 致敬【参考方案4】:对于像我这样的一些懒人来说,它只是将 Seq 转换为 varArgs!
【讨论】:
以上是关于`:_*`(冒号下划线星号)在 Scala 中有啥作用?的主要内容,如果未能解决你的问题,请参考以下文章