【问题标题】:Create Closure from Generic in Scala在 Scala 中从泛型创建闭包
【发布时间】:2012-07-17 19:11:10
【问题描述】:

我正在尝试做一些我不确定 Scala 的类型系统是否允许我做的事情。

我基本上想从通用定义创建一个闭包并返回该闭包,同时在内部执行一个相同类型的函数。

例如:

val f = async[(str:String, i:Int, b:BigInt) => Unit]({ (String, Int, BigInt) =>
  // Code here...
})

// 'f' would have a type of (String, Int, BigInt) => Unit and would wrap the passed anonymous function

定义的理论例子:

  def async[T](
    shell: Shell,
    success: T,
    failure: (Throwable) => Unit): T = {
        new T {
          val display = shell.getDisplay()
          display.asyncExec(new Runnable() {
            def run(): Unit = {
              try {
                success(_)
              } catch {
                case e:Throwable =>
                  failure(e)
              }
            }
          })
        }
  }

这将允许我拥有一个为 SWT 创建异步回调的简单系统,同时将 SWT 排除在我的业务逻辑之外。

【问题讨论】:

标签: scala swt


【解决方案1】:

您可以使用Shapeless 库更通用地执行此操作。我们定义wrap如下:

import shapeless._, Functions._

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

然后可以这样使用:

scala> val sum: (Int, Int) => Int = _ + _
sum: (Int, Int) => Int = <function2>

scala> val wrappedSum = wrap(sum)
wrappedSum: (Int, Int) => Int = <function2>

scala> wrappedSum(100, 1)
Before f
After f
res0: Int = 101

这适用于任何数量的函数。

所以在 Scala 中是可能的,尽管在没有 Shapeless 的情况下做一些等效的事情几乎肯定会让人头疼。

【讨论】:

  • 这看起来很有趣!而且它不需要任何(显着的)运行时开销,例如,通过使用反射?
  • 不,没有反思。类型类会有一些运行时开销,但不应过多。
  • 谢谢。这正是我想要的。这可能成为将匿名类转换为匿名函数的一种非常有用的模式。
【解决方案2】:

这样的事情怎么样:

scala> def wrap[T1, T2, T3, R](f: (T1, T2, T3) => R) = {
 |   (v1: T1, v2: T2, v3: T3) =>
 |     println("Before f")
 |     val r = f(v1, v2, v3)
 |     println("After f")
 |     r
 | }
wrap: [T1, T2, T3, R](f: (T1, T2, T3) => R)(T1, T2, T3) => R

scala> def foo(x: String, y: Int, z: BigInt) = (x, y, z)
foo: (x: String, y: Int, z: BigInt)(String, Int, BigInt)

scala> val wrapped = wrap(foo _)
wrapped: (String, Int, BigInt) => (String, Int, BigInt) = <function3>

scala> wrapped("foo", 42, 12345)
Before f
After f
res0: (String, Int, BigInt) = (foo,42,12345)

如果您要包装的函数可能有不同数量的参数,那么不幸的是,您必须为每个不同的参数定义一次包装函数:-(

【讨论】:

  • 感谢您的回答。不同数量的参数部分是不幸的:(。不过,您可以强制侦听器采用单个元组并以这种方式传递类型以绕过限制。能够转发泛型类型真是太棒了。我'但不确定 Scala 是否具有该功能:/.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-02
  • 2018-06-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多