Scala中的'Spread'参数?

Bre*_*ust 5 parameters dsl scala function-calls

有没有办法调用一个带有单个参数的Scala函数,给定一个数组(类似于ECMAScript 6中的JavaScript Spreads)?

ys = [10.0, 2.72, -3.14]
f(x, ...ys);
Run Code Online (Sandbox Code Playgroud)

最干净的语法是:

f(1, ys)
Run Code Online (Sandbox Code Playgroud)

但这似乎不可能.甚至f(1, ys:_*)不起作用(也没有f(ys:_*),因为编译器报告的参数太少 - 只填充第一个参数).

例:

def f (a:Int, b:Float, c:Float, d:Float): String

val x  = 1
val ys = List(10.0, 2.72, -3.14)  // note: non-Objects
val result = f(x, ys)  // intuitive, but doesn't work
Run Code Online (Sandbox Code Playgroud)

用例:将测试数据(来自集合)注入到接受单个参数的现有方法中.由于这些是测试用例,如果ys中的#params不匹配并且提供运行时错误或不正确的结果,那就很好了.

问题是Scala是否允许一个干净的语法来调用一个带有单个参数的函数,给定一组参数 - 而不是它是否是一个好的设计(尽管意见肯定是受欢迎的).

iwe*_*ein 5

将列表作为元组传递并不容易,因为类型不太匹配(稍后会详细介绍)。只要有足够的鞋拔和润滑,任何东西都适合:

"My hack" should {
  "allow a function to be called with Lists" in {

    def function(bar:String, baz:String)= bar+baz


    //turn the function into something that accepts a tuple
    val functionT = function _
    val functionTT = functionT.tupled

    val arguments = List("bar", "baz")

    //Give the compiler a way to try and turn a list into a tuple of the size you need
    implicit def listToTuple(args:List[String]) = args match { 
      case List(a, b) => (a, b)
      case _ => throw IllegalArgumentException("Trying to pass off %s as a pair".format(args))
    }

    //Shove it in and hope for the best at runtime
    val applied = functionTT(arguments)
    applied === "barbaz"
  }
}
Run Code Online (Sandbox Code Playgroud)

您可以通过将其他参数添加到列表中或通过 Schönfinkeling 将参数分配到两个不同的组中来扩展此方法。我不会走那条路。

从我的评论中,您可能已经注意到,我不喜欢导致出现此问题的设计。我展示的代码本质上是将函数包装在外观中的代码。为什么不好好做呢?

查看 Spray,您可能会发现他们的完整方法隐式接受大量不同的参数。他们为此使用的巧妙技巧被命名为“磁铁图案”。您可以做同样的事情,并为您选择接受的不同元组引入隐式转换到您的磁铁。