我最难理解何时能够或不能省略括号和/或句号,以及如何与_相互作用。
我对此的具体案例是
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;我认为这是一个次优的编程策略。这一切都有用吗?
答案 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 function和Scala Style Guide。此外,您可以随时向IDE寻求帮助,以便将代码重构为更简洁。