在 Scala 中将列表或映射解包为函数参数 [英] Unwrapping a list or map as function arguments in Scala

查看:45
本文介绍了在 Scala 中将列表或映射解包为函数参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以动态地将列表/元组/映射项作为 Scala 中函数的参数展开?我正在寻找与 Python 的 args/kwargs 等效的 Scala.

Is it possible to dynamically unwrap a list/tuple/map items as arguments to a function in Scala? I am looking for a Scala equivalent of Python's args/kwargs.

例如,在 Python 中,如果一个函数被定义为 def foo(bar1, bar2, bar3=None, bar4=1) 然后给出一个列表 x=[1,7] 和字典 y={'bar3':True, 'bar4':9} 你可以将 foo 称为 foo(*x, **y).

For instance, in Python if a function is defined as def foo(bar1, bar2, bar3=None, bar4=1) then given a list x=[1,7] and a dictionary y={'bar3':True, 'bar4':9} you can call foo as foo(*x, **y).

推荐答案

需要说明的是,以下是有效的 Python 代码:

Just to be clear, the following is valid Python code:

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 要求的编译时类型检查.让我们仔细看看.

However, there is no analogous Scala syntax. There are some similar things, but the main reason this is never going to be possible is that it would violate the compile-time type checking that Scala requires. Let's look more closely.

首先,考虑可变参数部分.在这里,您希望能够传入一个任意长度的参数列表,并让它填写相关的函数参数.这在 Scala 中永远行不通,因为类型检查器要求传递给函数的参数是有效的.在您的场景中, foo() 可以接受长度为 2 的参数列表 x,但不能少于此.但是由于任何 Seq 可以有任意数量的参数,类型检查器如何知道正在传递的 x 在编译时是有效的?

First, think about the varargs portion. Here you want to be able to pass in an arbitrary-length list of arguments and have it fill in the relevant function parameters. This will never work in Scala because the type checker requires that the parameters passed into a function be valid. In your scenario, foo() can accept a parameter list x of length two, but no less. But since any Seq can have an arbitrary number of parameters, how would the type checker know that the x being pass it is valid at compile time?

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

Second, think about the keywword arguments. Here you are asking for the function to accept an arbitrary Map of arguments and values. But you get the same problem: How can the compile-time type checker know that you are passing in all of the necessary arguments? Or, further, that they are the right types? After all, they example you give is a Map containing both a Boolean and an Int, which would have the type Map[String, Any], so how would the type checker know that this would match your parameter types?

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

You can do some similar things, but not this exactly. For example, if you defined your function to explicitly use varargs, you can pass in a Seq:

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

这是可行的,因为 Scala 知道它只需要零个或多个参数的序列,而 Seq 将始终包含零个或多个项目,因此它匹配.此外,它只有在类型也匹配时才有效;这里它期待一个整数序列,并得到它.

This works because Scala knows that it only needs a sequence of zero or more arguments, and a Seq will always contain zero or more items, so it matches. Further, it only works if the types match as well; here it's expecting a sequence of Ints, and gets it.

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

The other thing you can do is to pass in a tuple of arguments:

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 中的元组具有固定长度和每个位置的已知(可能不同)类型,类型检查器可以验证参数是否与预期参数.

Again, this works because Scala's type checker can verify that the arguments are valid. The function requires four arguments, of types Int, Int, Boolean, and Int, and since a tuple in Scala has a fixed length and known (and possibly different) types for each position, the type-checker can verify that the arguments match the expected parameters.

这篇关于在 Scala 中将列表或映射解包为函数参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆