在Scala中使用高阶函数时,命名参数vs _,点符号vs中缀操作,卷曲与圆括号

时间:2014-10-18 10:45:45

标签: scala type-inference higher-order-functions syntactic-sugar

我最难理解何时能够或不能省略括号和/或句号,以及如何与_相互作用。

我对此的具体案例是

val x: X = ???
val xss: List[List[X]] = ???
xss map x :: _ //this doesn't compile
xss map _.::(x) //this is the same as the above (and thus doesn't compile)

上述两个似乎与xss.map(_).::(x)

相同
xss map (x :: _) //this works as expected
xss map {x :: _} //this does the same thing as the above

同时,以下内容也失败了:

xss.map xs => x :: xs //';' expected but '=>' found.
xss.map x :: _ //missing arguments for method map in class List; follow this method with `_' if you want to treat it as a partially applied function
//so when I try following the method with _, I get my favourite:
xss.map _ x :: _ //Cannot construct a collection of type That with elements of type B based on a collection of type List[List[Main.X]]
//as opposed to
xss map _ x :: _ //missing parameter type for expanded function ((x$1) => xss.map(x$1).x(($colon$colon: (() => <empty>))))

现在,我经常玩#34;切换符号直到它编译&#34;我认为这是一个次优的编程策略。这一切都有用吗?

1 个答案:

答案 0 :(得分:2)

首先,我们需要区分xss.map(f)xss map f。根据{{​​3}},任何采用单个参数的方法都可以用作中缀运算符。

实际上Scala Documentation是这些方法之一。忽略完整签名以及它继承自TraversableLike的事实,签名如下:

final def map[B](f: (A) ⇒ B): List[B]

因此它需要一个参数,即f,它是一个类型为A => B的函数。因此,如果您将map method in List定义为

val mySize = (xs:List[Int]) => xs.size

你可以选择

xss.map(mySize)

xss map mySize

这是一个偏好问题,但根据function value,对于这种情况,后者是首选,除非它是复杂表达式的一部分,最好坚持使用点符号。

请注意,如果您选择使用点表示法,则始终需要使用括号来限定函数应用程序!这就是为什么以下都没有成功编译。

xss.map xs => x :: xs // Won't compile
xss.map x :: _ // Won't compile
xss.map _ x :: _ // Won't compile

但是大部分时间而不是传递函数值,您需要传递Scala Style Guide(又名function literal)。在这种情况下,如果您使用点符号,则需要xss.map(_.size)之类的内容。但是如果你使用中缀符号,那将是一个优先事项。

例如

xss map x :: _ // Won't compile!
由于运算符优先级,

不起作用。因此,您需要使用括号来区分xss map (x :: _)编译器的情况。

使用花括号而不是括号有一个非常明确和简单的规则。同样,只有一个参数的任何函数都可以用大括号而不是括号来表示,对于中缀和点符号都是如此。所以下面的语句将被编译。

xss.map{x :: _}
xss map {x :: _}

为避免混淆,您可以从点表示法和参数的显式类型开始。在编译之后 - 并且可能为您的代码编写了一些单元测试 - 您可以通过删除不必要的类型,使用中缀表示法,并在有意义的地方使用花括号而不是括号来开始重构代码。

为此,您可以参考有关Scala编码风格的anonymous functionScala Style Guide。此外,您可以随时向IDE寻求帮助,以便将代码重构为更简洁。