。用scala替代

时间:2011-12-16 17:37:34

标签: scala

我来自Groovy,它在每个接受单参数闭包的类型上都有.with方法;参数是调用.with方法的对象。这允许一种非常酷的扩展功能链功能的技术,这使您无需引入临时变量,使代码更加容易,使其更容易阅读并做其他细节。

我希望能够做到这样的事情:

Seq(1, 2, 3, 4, 5)
  .filter(_ % 2 == 0)
  .with(it => if (!it.isEmpty) println(it))

而不是

val yetAnotherMeaninglessNameForTemporaryVariable = 
  Seq(1, 2, 3, 4, 5).filter(_ % 2 == 0)
if (!yetAnotherMeaninglessNameForTemporaryVariable.isEmpty) 
  println(yetAnotherMeaninglessNameForTemporaryVariable)

换句话说,在第一个例子中,.with有点类似于.foreach,但不是通过对象的项目进行迭代,而是在对象本身上调用一次。因此it等于Seq(1, 2, 3, 4, 5).filter(_ % 2 == 0)

由于我很惊讶在Scala中没有找到类似的东西,我的问题是:

  • 我错过了什么吗?
  • 是否有Scala原生的替代技术?
  • 如果没有,是否有任何正当理由说明为什么Scala中没有实现此功能?

更新 已在Scala问题跟踪器上发布了相应的功能请求:https://issues.scala-lang.org/browse/SI-5324。请投票和推广

6 个答案:

答案 0 :(得分:12)

标准库中不存在任何此类方法,但定义自己的方法并不困难。

implicit def aW[A](a: A) = new AW(a)
class AW[A](a: A) {
  def tap[U](f: A => U): A = {
    f(a)
    a
  }
}

val seq = Seq(2, 3, 11).
          map(_ * 3).tap(x => println("After mapping: " + x)).
          filter(_ % 2 != 0).tap(x => println("After filtering: " + x))

编辑:(回应评论)

哦,我误会了。你需要的是Scalaz库。它名称为|>(称为管道运算符)。有了它,您的示例将如下所示:

Seq(1, 2, 3, 4, 5).filter(_ % 2 == 0) |> { it => if(!it.isEmpty) println(it) }

如果您不能使用Scalaz,您可以自己定义运算符:

implicit def aW[A](a: A) = new AW(a)
class AW[A](a: A) {
  def |>[B](f: A => B): B = f(a)
}

在现有类型上使用有用的方法并不是一个坏习惯。你应该谨慎使用隐式转换,但我认为这两个组合器很常见,因为它们的皮条客是合理的。

答案 1 :(得分:7)

Scala中包含此模式的一些语法:

Seq(1, 2, 3, 4, 5).filter(_ % 2 == 0) match { case it => if (!it.isEmpty) println(it) }

然而,这不是公认的习惯用法,所以你应该避免(ab)使用它。

如果您不喜欢为虚拟变量发明负载和名称,请记住您可以使用范围大括号:

val importantResult = {
  val it = Seq(1,2,3).filter(_ % 2 == 0)
  if (!it.isEmpty) println(it)
  it
}

val otherImportantResultWithASpeakingVariableName = {
  val it = // ...
  /* ... */
  it
}

答案 2 :(得分:3)

试试这样。

println(Seq(1, 2, 3, 4, 5).filter(_ % 2 == 0).ensuring(!_.isEmpty))

如果不满足条件,则抛出断言异常。

答案 3 :(得分:1)

记得按姓名打电话?也许它可以为你提供你想要的能力:

object Test {
 def main(args: Array[String]) {
   delayed(time());
 }

 def time() = {
    println("Getting time in nano seconds")
    System.nanoTime
 }

 def delayed( t: => Long ) = {
   println("In delayed method")
   println("Param: " + t)
   t
 }
}

http://www.tutorialspoint.com/scala/functions_call_by_name.htm

中所述

答案 4 :(得分:1)

虽然我更喜欢其他解决方案(因为它们更本地化,因此更容易理解),不要忘记你可以

{ val x = Seq(1,2,3,4,5).filter(_ % 2 == 0); println(x); x }

避免在无意义的变量上发生名称冲突,并将它们限制在适当的范围内。

答案 5 :(得分:1)

这只是功能应用程序f(x)翻转头:x.with(f) ...如果您正在寻找在Scala中执行with的惯用方法,请取消它:

(it => if (!it.isEmpty) println(it)) (Seq(1, 2, 3, 4, 5).filter(_ % 2 == 0))

同样,如果您想要x.with(f).with(g),只需使用g(f(x)) ...