Scala代码的接受/推荐语法是什么,有很多方法链接?

ove*_*ink 22 syntax coding-style scala method-chaining

在Scala中,我倾向于使用val赋值在许多较小的表达式上编写大型链式表达式.在我的公司,我们已经为这种类型的代码改进了一种风格.这是一个完全人为的例子(想法是显示一个包含大量链接调用的表达式):

import scala.util.Random
val table = (1 to 10) map { (Random.nextInt(100), _) } toMap

def foo: List[Int] =
  (1 to 100)
    .view
    .map { _ + 3 }
    .filter { _ > 10 }
    .flatMap { table.get }
    .take(3)
    .toList
Run Code Online (Sandbox Code Playgroud)

Daniel Spiewak的Scala风格指南(pdf),我一般都喜欢,它表明链式方法调用中的前导点符号可能不好(参见doc:Method Invocation/Higher-Order Functions),尽管它不包括多行表达式直接这样.

是否有另一种更为接受/惯用的方式来编写上述函数foo

更新:2011年6月28日

下面有很多很棒的答案和讨论.似乎没有100%"你必须这样做"答案,所以我将接受最受欢迎的答案,这是目前的理解方法.就个人而言,我认为我现在要坚持使用前导符号,并接受随之而来的风险.

Kev*_*ght 16

这个例子有点不切实际,但对于复杂的表达式来说,使用理解通常要简洁得多:

def foo = {
  val results = for {
    x <- (1 to 100).view
    y = x + 3 if y > 10
    z <- table get y
  } yield z
  (results take 3).toList
}
Run Code Online (Sandbox Code Playgroud)

这里的另一个优点是,您可以命名计算的中间阶段,并使其更加自我记录.

如果简洁是你的目标,那么这可以很容易地变成一个单行(这里的无点样式有帮助):

def foo = (1 to 100).view.map{3+}.filter{10<}.flatMap{table.get}.take(3).toList
//or
def foo = ((1 to 100).view map {3+} filter {10<} flatMap {table.get} take 3).toList
Run Code Online (Sandbox Code Playgroud)

并且,一如既往,尽可能优化您的算法:

def foo = ((1 to 100).view map {3+} filter {10<} flatMap {table.get} take 3).toList
def foo = ((4 to 103).view filter {10<} flatMap {table.get} take 3).toList
def foo = ((11 to 103).view flatMap {table.get} take 3).toList
Run Code Online (Sandbox Code Playgroud)


Ale*_*ert 11

我将整个表达式包装成一组括号以分组并尽可能避免使用点,

def foo: List[Int] =
  ( (1 to 100).view
    map { _ + 3 }
    filter { _ > 10 }
    flatMap { table.get }
    take(3)
    toList )
Run Code Online (Sandbox Code Playgroud)

  • 有趣,但似乎有点像黑客.我更喜欢这些圆点,所以每条线都更清晰,而不必四处寻找括号. (3认同)

psp*_*psp 6

以下是即兴演奏的方式.你不能出错.

(specMember
  setInfo   subst(env, specMember.info.asSeenFrom(owner.thisType, sym.owner))
  setFlag   (SPECIALIZED)
  resetFlag (DEFERRED | CASEACCESSOR | ACCESSOR | LAZY)
)
Run Code Online (Sandbox Code Playgroud)

正宗编译源码!


kir*_*uku 5

我更喜欢vals:

def foo = {
  val range = (1 to 100).view
  val mappedRange = range map { _+3 }
  val importantValues = mappedRange filter { _ > 10 } flatMap { table.get }
  (importantValues take 3).toList
}
Run Code Online (Sandbox Code Playgroud)

因为我不知道你想用你的代码做什么,所以我为vals 选择了随机名.选择vals而不是其他提到的解决方案有一个很大的优势:

很明显你的代码做了什么.在你的榜样,并在大多数其他的答案中提到的解决方案,任何人都不会知道一见钟情它做什么.一个表达式中的信息太多.只有在@Kevin提到的for-expression中,才有可能选择说出名字,但我不喜欢它们,因为:

  1. 他们需要更多代码
  2. 由于模式匹配声明的值,它们会变慢(我在这里提到).
  3. 只是我的意见,但我认为他们看起来很难看