`:_*`(冒号下划线星号)在 Scala 中做什么?

发布于 2024-11-08 08:04:28 字数 558 浏览 1 评论 0原文

我有这个问题中的以下代码:

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 连接,然后呢? : _* 的作用是什么?

I have the following piece of code from 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!")
}

Everything in it is pretty clear, except this piece: child ++ newChild : _*

What does it do?

I understand there is Seq[Node] concatenated with another Node, and then? What does : _* do?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

开始看清了 2024-11-15 08:04:28

它“splats”1序列。

查看

new Elem(prefix: String, label: String, attributes: MetaData, scope: NamespaceBinding,
         child: Node*)

被调用的

new Elem(prefix, label, attributes, scope,
         child1, child2, ... childN)

构造函数签名,但这里只有一个序列,而不是 child1child2 等,因此这允许将结果序列用作输入到构造函数。


1 这在 SLS 中没有一个可爱的名字,但这里是详细信息。重要的是它改变了 Scala 将参数绑定到具有重复参数的方法的方式(如上面的 Node* 所示)。

_*类型注释在SLS的“4.6.2重复参数”中介绍。

<块引用>

参数部分的最后一个值参数可以带有“*”后缀,例如(..., x:T )。方法内这种重复参数的类型是
序列类型 scala.Seq[T]。具有重复参数的方法 T * take
类型 T 的可变数量的参数。也就是说,如果方法 m 的类型为
(p1 : T1, . . . , pn : Tn,ps : S
)U 应用于参数 (e1, . . . , ek),其中 k >= n,则
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])**

It "splats"1 the sequence.

Look at the constructor signature

new Elem(prefix: String, label: String, attributes: MetaData, scope: NamespaceBinding,
         child: Node*)

which is called as

new Elem(prefix, label, attributes, scope,
         child1, child2, ... childN)

but here there is only a sequence, not child1, child2, etc. so this allows the result sequence to be used as the input to the constructor.


1 This doesn't have a cutesy-name in the SLS, but here are the details. The important thing to get is that it changes how Scala binds the arguments to the method with repeated parameters (as denoted with Node* above).

The _* type annotation is covered in "4.6.2 Repeated Parameters" of the SLS.

The last value parameter of a parameter section may be suffixed by “*”, e.g. (..., x:T ). The type of such a repeated parameter inside the method is then
the sequence type scala.Seq[T]. Methods with repeated parameters T * take
a variable number of arguments of type T . That is, if a method m with type
(p1 : T1, . . . , pn : Tn,ps : S
)U is applied to arguments (e1, . . . , ek) where k >= n, then
m is taken in that application to have type (p1 : T1, . . . , pn : Tn,ps : S, . . . , ps0S)U,
with k ¡ n occurrences of type S where any parameter names beyond ps are
fresh. The only exception to this rule is if the last argument is marked to be
a sequence argument via a _
type annotation. If m above is applied to arguments (e1, . . . , en,e0 : _
), then the type of m in that application is taken to be
(p1 : T1, . . . , pn : Tn,ps :scala.Seq[S])**

合约呢 2024-11-15 08:04:28
  • child ++ newChild - 序列
  • : - 类型归属,帮助编译器理解该表达式的类型的提示
  • _* - 占位符接受任何值 + vararg 运算符

child ++ newChild : _*Seq[Node] 扩展为 Node* (告诉编译器我们正在而不是使用可变参数,而不是序列)。对于只能接受可变参数的方法特别有用。

  • child ++ newChild - sequence
  • : - type ascription, a hint that helps compiler to understand, what type does that expression have
  • _* - placeholder accepting any value + vararg operator

child ++ newChild : _* expands Seq[Node] to Node* (tells the compiler that we're rather working with a varargs, than a sequence). Particularly useful for the methods that can accept only varargs.

清欢 2024-11-15 08:04:28

上面的所有答案看起来都很棒,但只需要一个示例来解释这一点。
如下:

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]*

现在我们知道 :_* 的作用是告诉编译器:请解压此参数并将这些元素绑定到函数调用中的 vararg 参数,而不是将 x 作为单个参数。

简而言之, :_* 是为了消除将参数传递给 vararg 参数时的歧义。

All the above answer looks great, but just need a sample to explain this .
Here it is :

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]*

So now we know what :_* do is to tell compiler : please unpack this argument and bind those elements to the vararg parameter in function call rather than take the x as a single argument .

So in a nutshell, the :_* is to remove ambiguity when pass argument to vararg parameter.

浅听莫相离 2024-11-15 08:04:28

对于像我这样的懒人来说,它只是将集合值转换为 varArgs!

For some of the lazy folks like me, it just converts collection values to varArgs!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文