是否可以动态解包list / tuple / map项作为Scala中函数的参数?我正在寻找与Python的args
/ kwargs
相同的Scala。
例如,在Python中,如果函数定义为def foo(bar1, bar2, bar3=None, bar4=1)
,然后给定列表x=[1,7]
和字典y={'bar3':True, 'bar4':9}
,则可以将foo
称为foo(*x, **y)
答案 0 :(得分:11)
为了清楚起见,以下是有效的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)
但是,没有类似的Scala语法。有一些类似的东西,但这是永远不可能的主要原因是它会违反Scala所需的编译时类型检查。让我们仔细看看。
首先,考虑一下varargs部分。在这里,您希望能够传入任意长度的参数列表,并填写相关的函数参数。这在Scala中永远不会起作用,因为类型检查器要求传递给函数的参数有效。在您的方案中,foo()
可以接受长度为2但不小于的参数列表x
。但是因为任何Seq
都可以有任意数量的参数,所以类型检查器如何知道传递它的x
在编译时是有效的?
其次,考虑关键字论点。在这里,您要求函数接受任意Map
个参数和值。但是你得到了同样的问题:编译时类型检查器如何知道你传递了所有必要的参数?或者,进一步说,他们是正确的类型?毕竟,他们给出的示例是包含布尔值和Int的Map,其类型为Map[String, Any]
,那么类型检查器如何知道这将与您的参数类型匹配?
你可以做一些类似的事情,但不是这样。例如,如果您将函数定义为显式使用varargs,则可以传入Seq:
def foo(bar1: Int*) = println(f"bar1=$bar1")
val x = Seq(1, 2)
foo(x:_*)
这是有效的,因为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)
同样,这是有效的,因为Scala的类型检查器可以验证参数是否有效。该函数需要四个参数,类型为Int,Int,Boolean和Int,并且由于Scala中的元组具有固定长度和每个位置的已知(可能不同)类型,因此类型检查器可以验证参数是否与预期参数。
答案 1 :(得分:1)
原始答案没有提到处理地图作为对的列表 - 它可以很容易地转换为地图(甚至 - >运算符只是对的简写)。
def parse(options: (String, String)*) = println (options.toMap)
答案 2 :(得分:1)
OQ的边缘大小写的排序但是如果你想传递一个case类的参数Map,这似乎有效:
scala> case class myCC(foo: String = "bar", negInt: Int = -1)
scala> val row = myCC()
scala> println(row)
myCC(bar,-1)
scala> val overrides = Map("foo" -> "baz")
scala> row.getClass.getDeclaredFields foreach { f =>
f.setAccessible(true)
overrides.foreach{case (k,v) => if (k == f.getName) f.set(row, v)}
}
scala> println(row)
myCC(baz,-1)
(借鉴Scala: How to access a class property dynamically by name?)
答案 3 :(得分:0)
您可以使用varargs语法:
def printAll(strings: String*) {
strings.map(println)
}
不,你可以这样使用这个功能:
printAll("foo")
所以:
printAll("foo", "bar")
左右:
printAll("foo", "bar", "baz")