【问题标题】:Function taking another function of arbitrary arity as argument以任意数量的另一个函数作为参数的函数
【发布时间】:2020-01-19 12:29:50
【问题描述】:

我有一系列接受函数作为参数的函数 (func),它们之间的唯一区别是 func 接受不同数量的参数。

  def tryGet[T,A](func: (A) => T)
  def tryGet[T,A,B](func: (A,B) => T)
  ...       [T,A,B,C...]

有没有办法让函数接受具有任意长度参数列表的函数?

我尝试使用可变长度参数列表,例如func:(A*),但在传递任何函数时遇到了麻烦,因为它现在需要Seq[A]

【问题讨论】:

  • 如果你不知道函数参数的数量和类型。您希望如何调用/使用它?
  • @LuisMiguelMejíaSuárez 我原以为可以这样打电话:func()。例如,如果我想传入函数def getSomething(int:Int) = Future.successful(int),通过像tryGet( (int:Int) => getSomething(int) ) 那样调用tryGet,我使用的是func() map { ... handle exceptions and return an Option instead}。我要解决的更广泛的问题是,我是否可以包装大量引发异常的 API 调用,以便它们在 NoSuchElementExceptions 的情况下抛出 Options。
  • 例如tryGet 不应该知道或关心函数是什么,它只知道如果func 抛出了一些特定的异常,它应该返回None,如果没有,那么它应该返回Some(T)
  • 你希望func()如何编译?如果它可能需要任何数量的参数?你真的不想传递任何类型的函数。而是在Future[T] 上产生的任何类型的块并调用它。类似于def tryGet[T](block: => Future[T]): Future[Option[T]] = block.recoverWith(...)
  • 另一种选择是只接收一个函数A => T,其中A 是任何类型的产品。因此,如果您需要两个参数,请将它们作为元组传递。

标签: scala shapeless arity


【解决方案1】:

为什么不直接使用 scala.util.Try?或者只是将参数传递给 tryGet,而不是作为块,而是作为类型 T 的别名参数?

【讨论】:

  • 谢谢,但我不知道该怎么做,举个例子就好了!
  • Try(unaryFunc(a)) Try(binaryFunc(a, b)).toOption 或者,如果您想手动完成,def tryGet[T](func: => T) = try { Some(func) } catch { case ex: Exception => None }
【解决方案2】:

你可以尝试使用shapeless.ops.function.FnToProduct

def tryGet[F: FnToProduct](func: F) = ???

val f1: Int => String = ???
val f2: (Int, Int) => String = ???
val f3: (Int, Int, Int) => String = ???

tryGet(f1)
tryGet(f2)
tryGet(f3)

https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0#facilities-for-abstracting-over-arity

【讨论】:

    猜你喜欢
    • 2021-03-28
    • 2013-03-20
    • 1970-01-01
    • 2022-01-11
    • 2012-09-24
    • 1970-01-01
    • 1970-01-01
    • 2016-07-21
    相关资源
    最近更新 更多