【问题标题】:Invoking anonymous closure调用匿名闭包
【发布时间】:2012-02-21 14:21:31
【问题描述】:

编辑
好的,这里有很好的反馈,让我指出了正确的方向。调用匿名闭包的用例在 Scalatra 路由层中。我有一堆路由,它们按各种类型分组在一起,在这个例子中,是团队共有的请求:

class Router {
  type TeamType <: _Controller with _Team

  get("""(schedules|rosters|teamresults|teamstats)/\d{8}""".r) {
    val clazz :: date = captures

    val obj = (clazz match {
      case "schedules" => new RosterController
      case "rosters" => new ScheduleController
    }).asInstanceOf[TeamType]

    obj.show(date)
  }
}

通过将匹配表达式包装在一个自调用的匿名闭包中,我们避免在每个匹配的情况下附加“FooController.asInstanceOf[TeamType]”,而是在返回的实例上进行类型转换,保持过程中的不变性(即不能“val obj = clazz match {...}”后跟类型转换,因为 obj 已经被验证)

我相信这是在基于字符串类名创建对象实例时可以得到的最简短的形式。当然,话虽这么说,但很可能有一种 FP 方法可以更简洁地完成这项工作......

无论如何,很酷的东西,缺少来自 Groovy 的匿名闭包,现在我发现 Scala 也涵盖了这一点 ;-)

原创
不知道如何在 Scala 中实现这一点。在 Groovy 中,您可以像这样定义和调用匿名闭包:

{String s-> println(s) }("hello")

Scala 中的等价物是什么?另外,除了返回 Unit,如何指定返回类型?

谢谢

【问题讨论】:

  • asInstanceOf 的使用是有效的这种情况非常罕见,而且这看起来不像。如果类型归属在此处不起作用,则该语句可能不正确。
  • 为什么它不起作用?闭包返回一个对象并将 asInstanceOf 强制转换为所需的类型。我还没有测试,但编译器显示了正确的类型,并提供了预期的自动完成方法。
  • 你搞错了:asInstanceOf never 导致编译时错误——你明确告诉编译器相信你,即使它认为你错了。如果代码正确,则键入 ascription 就足够了。例外情况是具体化、反序列化和标记特征,以及一些语义可以保证类型本身无法保证的情况。
  • 啊,好吧,不知道,+1。在这种情况下,虽然根本不是类型安全的,但除非正则表达式匹配,否则不会处理路由本身;因此我知道我得到了一个长度为 2 的 Seq[String] 来创建 clazz & date vals。像 xml 一样,存在对字符串进行胖指法的可能性,但除此之外我可以忍受它,就像自调用对象工厂一样 ;-)

标签: scala closures invoke anonymous


【解决方案1】:
((s : String) => println(s))("hello")

至于返回类型,让Scala自己推断吧。

scala> ((x : Int) => x < 4)(3)
res0: Boolean = true

【讨论】:

  • 谢谢,用括号代替花括号就可以了。 re:返回类型,闭包实际上将包含匹配块的结果,这是一个我会知道其类型的对象实例;因此,如何在闭包本身上指定返回类型的问题(所以我不必这样做,“case x => new Foo with CommonSuperType”)
  • @virtualeyes:抱歉,我不知道闭包上显式返回类型的语法。实际上,我上次在 Scala 中做任何事情是很久以前的事了 :)
  • @virtualeyes,大括号也可以,但您必须明确调用apply{ (s: String) =&gt; println(s) } apply "hello".
  • @virtualeyes,这是您指定参数类型和返回类型的方式:({ s =&gt; println(s) } : String =&gt; Unit) apply "hello"
  • 您可以通过在最后一个值上声明返回类型来获得显式返回类型,例如((s: String) =&gt; println(s): Any)("hello") 或通过说明整个函数的类型,例如((s =&gt; println(s)): (String =&gt; Any))("hello")
【解决方案2】:

要添加到@larsmans 的答案,您也可以让 Scala 编译器推断参数类型。 Scala 类型推断从左到右流动,因此您必须相应地排列术语。我们可以通过定义一个管道转发操作符|&gt; 来做到这一点,这样:

x |> f = f(x)

它在 Scalaz 中可用。如果你不想使用 Scalaz,it's not hard to define it yourself

使用示例:

scala> "hello" |> { s => println(s) }
hello

scala> "hello" |> println
hello

scala> 3 |> { y => y < 4 }
res23: Boolean = true

scala> 3 |> { _ < 4 }
res24: Boolean = true

【讨论】:

  • @virtualeyes,哎呀,没有注意到问这个问题的是同一个 OP。
  • @missingfactor,是的,看起来很熟悉 ;-)
猜你喜欢
  • 1970-01-01
  • 2013-04-08
  • 2021-12-09
  • 2021-12-10
  • 2021-09-29
  • 1970-01-01
  • 2017-01-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多