是否可以动态解包列表/元组/映射项作为Scala中函数的参数?我正在寻找一个类似Python的Scala args
/kwargs
。
例如,在Python中,如果函数被定义为 def foo(bar1, bar2, bar3=None, bar4=1)
然后给出一个清单 x=[1,7]
和一本字典 y={'bar3':True, 'bar4':9}
你可以打电话 foo
如 foo(*x, **y)
。
是否可以动态解包列表/元组/映射项作为Scala中函数的参数?我正在寻找一个类似Python的Scala args
/kwargs
。
例如,在Python中,如果函数被定义为 def foo(bar1, bar2, bar3=None, bar4=1)
然后给出一个清单 x=[1,7]
和一本字典 y={'bar3':True, 'bar4':9}
你可以打电话 foo
如 foo(*x, **y)
。
为了清楚起见,以下是有效的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()
可以接受参数列表 x
长度为2,但不低于。但是既然如此 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中的元组具有固定长度以及每个位置的已知(可能不同)类型,因此类型检查器可以验证参数是否与预期参数。
为了清楚起见,以下是有效的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()
可以接受参数列表 x
长度为2,但不低于。但是既然如此 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中的元组具有固定长度以及每个位置的已知(可能不同)类型,因此类型检查器可以验证参数是否与预期参数。
原始答案没有提到处理Map作为对列表 - 它可以很容易地转换为map(偶数 - >运算符只是对的简写)。
def parse(options: (String, String)*) = println (options.toMap)
OQ的边缘情况的排序,但如果你想传递一个案例类的参数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:如何通过名称动态访问类属性?)
您可以使用varargs语法:
def printAll(strings: String*) {
strings.map(println)
}
不,你可以使用这个功能:
printAll("foo")
所以:
printAll("foo", "bar")
或者:
printAll("foo", "bar", "baz")