在Scala中将列表或映射展开为函数参数

Abr*_*suf 11 python scala

是否可以动态解包列表/元组/映射项作为Scala中函数的参数?我正在寻找一个Scala相当于Python的args/ kwargs.

例如,在Python如果一个函数定义为def foo(bar1, bar2, bar3=None, bar4=1)再给予一个列表x=[1,7]和字典y={'bar3':True, 'bar4':9}可以调用foofoo(*x, **y).

dhg*_*dhg 12

为了清楚起见,以下是有效的Python代码:

def foo(bar1, bar2, bar3=None, bar4=1): print("bar1="+str(bar1)+" bar2="+str(bar2)+" bar3="+str(bar3)+" bar4="+str(bar4))
x=[1,7]
y={'bar3':True, 'bar4':9}
foo(*x,**y)
Run Code Online (Sandbox Code Playgroud)

但是,没有类似的Scala语法.有一些类似的东西,但这是永远不可能的主要原因是它会违反Scala所需的编译时类型检查.让我们仔细看看.

原因

首先,考虑一下varargs部分.在这里,您希望能够传入任意长度的参数列表,并填写相关的函数参数.这在Scala中永远不会起作用,因为类型检查器要求传递给函数的参数有效.在您的方案中,foo()可以接受x长度为2 的参数列表,但不能少于.但是因为任何Seq参数都可以有任意数量的参数,所以类型检查器如何知道x传递它在编译时是否有效?

其次,考虑关键词论点.在这里,您要求函数接受任意Map参数和值.但是你得到了同样的问题:编译时类型检查器如何知道你传递了所有必要的参数?或者,进一步说,他们是正确的类型?毕竟,他们给出的示例是一个包含布尔值和Int的Map,它具有类型Map[String, Any],那么类型检查器如何知道这将匹配您的参数类型?

一些解决方案

Scala的varargs

你可以做一些类似的事情,但不是这个.例如,如果您将函数定义为显式使用varargs,则可以传入Seq:

def foo(bar1: Int*) = println(f"bar1=$bar1")
val x = Seq(1, 2)
foo(x:_*)
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为Scala知道它只需要一个零个或多个参数的序列,而Seq将始终包含零个或多个项目,因此它匹配.此外,它只适用于类型匹配的情况; 在这里它期待一系列的Ints,并得到它.

tupled

你可以做的另一件事是传入一个参数元组:

def foo(bar1: Int, bar2: Int, bar3: Boolean = false, bar4: Int = 1) = println(f"bar1=$bar1 bar2=$bar2 bar3=$bar3 bar4=$bar4")
val x = (1, 2, true, 9)
(foo _).tupled(x)
Run Code Online (Sandbox Code Playgroud)

同样,这是有效的,因为Scala的类型检查器可以验证参数是否有效.该函数需要四个参数,类型为Int,Int,Boolean和Int,并且由于Scala中的元组具有固定长度以及每个位置的已知(可能不同)类型,因此类型检查器可以验证参数是否与预期参数.