【问题标题】:Replace Asynchronous Anonymous Class with Function用函数替换异步匿名类
【发布时间】:2012-07-18 00:24:54
【问题描述】:

我认为无形库可以做到这一点。

我正在使用 shapeless 将匿名类转换为闭包。这需要使用来自 FnHListerAux 特征的 hlisted。

我想要做的就是摆脱传入的虚拟函数,并围绕该函数返回一个闭包,该闭包具有与F 相同的类型签名。如果没有异步执行的匿名类,这将很容易。有没有办法解决这个问题?

def async[F, A <: HList, R](
  shell: Shell,
  success: F,
  failure: FunctionTypes.Failure,
  dummy: F)(implicit h: FnHListerAux[F, A => R],
            u: FnUnHListerAux[A => R, F]): F =
{ (args: A) =>

  require(shell != null, "Shell cannot be null")
  require(shell.getDisplay() != null, "The shell must have a display")

  val display = shell.getDisplay()
  display.asyncExec(new Runnable() {
    def run(): Unit = {
      try {
        success.hlisted(args)
      } catch {
        case e: Throwable =>
          failure(e)
      }
    }
  })

  dummy.hlisted(args)
}.unhlisted

【问题讨论】:

  • 如果你需要这样毫无意义的东西,你的算法肯定有一些严重的问题。试着解释一下你需要什么。
  • 当然,那是个好主意。我对 Scala 很陌生。我仍然很好奇你是否真的可以替换函数的主体。但是,对于我的实际问题,解决方案很可能在于无形库,这远远超出了我的知识水平,我仍在努力了解它的本质。

标签: scala shapeless


【解决方案1】:

我将从简化一点开始。假设我有一个函数f。我事先不知道它是什么,我也不关心它返回什么。我想用一些功能包装它并获得一个具有相同参数类型的函数。我也不关心这个结果函数返回什么,所以我不妨让它返回Unit。

您可以编写一堆(嗯,22 个)函数,如下所示:

def wrap[A](f: A => Unit): A => Unit = ???
def wrap[A, B](f: (A, B) => Unit): (A, B) => Unit = ???
def wrap[A, B, C](f: (A, B, C) => Unit): (A, B, C) => Unit = ???

但你不想。

Shapeless 绝对可以更通用地帮你解决这个问题:

def wrap[F, A <: HList](f: F)(
  implicit h: FnHListerAux[F, A => Unit], u: FnUnHListerAux[A => Unit, F]
): F = { (args: A) =>
  println("Before!"); f.hlisted(args); println("After!")
}.unhlisted

这给了我们:

scala> def f(i: Int, s: String) { println(s * i) }
f: (i: Int, s: String)Unit

scala> val wf = wrap(f _)
wf: (Int, String) => Unit = <function2>

scala> wf(3, "ab")
Before!
ababab
After!

请注意,f 可以返回除 Unit 之外的其他内容,但这仍然有效,因为 Scala 中的所有内容都是 Unit 并且 FunctionN 特征的返回类型是协变的。

将这种方法应用于您的代码,我们得到以下结果:

def async[F, A <: HList](
  shell: Shell, success: F, failure: FunctionTypes.Failure
)(
  implicit h: FnHListerAux[F, A => Unit], u: FnUnHListerAux[A => Unit, F]
): F = { (args: A) =>
  require(shell != null, "Shell cannot be null")
  require(shell.getDisplay() != null, "The shell must have a display")

  val display = shell.getDisplay()
  display.asyncExec(new Runnable() {
    def run(): Unit = {
      try {
        success.hlisted(args)
      } catch {
        case e: Throwable =>
          failure(e)
      }
    }
  })
}.unhlisted

不需要dummy。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-10
    • 2020-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    相关资源
    最近更新 更多