我来自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问题跟踪器上发布了相应的功能请求:https://issues.scala-lang.org/browse/SI-5324。请投票和推广
答案 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))
...