将列表作为单独的函数参数传递

5

我有一个函数def f(a: Int, b: Int, c: Int, d: Int, ...),我想在单元测试中提供一系列连续的整数作为参数。

有没有简洁的方法将(1 to N).toList提供给f?由于该函数不是def f(x: Int*),因此我不能简单地使用list: _*,其中list是整数列表。


作为注释写下来,因为它不是一个完整的答案,但可能会让你走上正确的道路:您可以将函数柯里化,使其成为“Int => Int => Int => Int => Int”,然后通过“foldLeft”逐个应用它们到函数中。 这个问题详细说明了这一点: https://dev59.com/6Wsz5IYBdhLWcg3w3rwJ 如果您有一个元组而不是列表,则可以将其应用于“f.tupled”,但如果您有一个列表,则忘记它。 - slouc
2个回答

2
我认为在标准的Scala中无法以类型安全的方式完成它,但是使用Shapeless库可以实现。即使您在项目中不使用此库,也可以仅依赖于测试范围。
以下是代码示例:
import shapeless._
import shapeless.ops.function._
import shapeless.ops.traversable._

def applyToList[F, HL <: HList, R](f: F)(args: List[Any])(implicit
  // convert `(T1, T2, ...) => R` to a function from a single HList argument `HL => R`
  fnToProduct: FnToProduct.Aux[F, HL => R],  
  // convert the argument list to the HList, expected by the converted function
  toHList: FromTraversable[HL]
): R = {
  toHList(args) match {
    case Some(hargs) => fnToProduct(f)(hargs)
    case None => sys.error("argument list not applicable to function")
  }
}

使用它就像这样简单:
def f(a: Int, b: Int, c: Int, d: Int): Any = ???
applyToList(f _)(List(1, 2, 3, 4))

但是请注意需要显式的 eta-conversion f _,因为 Scala 编译器并不知道 F 是一个函数。
你可以改变定义来返回 Option[R],因为在编译时无法确定提供的 List 是否适合该函数。例如,参数列表可能具有不匹配的元素数量。但如果这是用于单元测试,你也可以抛出异常。

1
如果你无法修改f(),那么你就有些束手无策了。你可以做一件(不是很好的)事情,写一个隐式翻译器。
假设f()需要4个Int参数。
implicit class Caller4[A,R](func: (A,A,A,A)=>R) {
  def call(as :A*) :R = func(as(0),as(1),as(2),as(3))
}

(f _).call(1 to 4:_*)    //call f(1,2,3,4)

好消息是,这适用于任何/所有需要4个相同类型参数的方法。
坏消息是,每个所需参数数量都需要不同的翻译器,并且如果您使用过少的参数调用call(),编译器将无法捕获它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接