【问题标题】:Elements of Scala Style? [closed]Scala 风格的元素? [关闭]
【发布时间】:2009-08-15 14:07:43
【问题描述】:

白天我写 C#。我所做的一切都经过微软代码分析和静态分析工具,因此我的 C# 具有非常规则的结构和布局。很明显,我写的代码有一定的风格。这是部分原因,因为我别无选择(如果我错过了逗号之前的空格,它将无法编译),但拥有常规外观的代码,知道在哪里寻找东西等也很好。

周末我会进入 Scala。查看 Scala API 和 Lift web 框架源,我显然看不到任何标准化的样式。例如,让我大吃一惊的一件事是每个班级都没有单独的文件。另一个例子是括号和大括号缺乏一致性。

我知道这可能有几个原因:首先,使用开源(或爱好)代码确保没有完全记录明显的方法不是优先考虑的问题。其次,案例类之类的东西将 20 行的类声明缩减为一行。第三,C# 是一种更“扁平化”的语言:除非它是一个复杂的LINQ 语句,否则嵌套的括号、大括号和方括号的数量不会那么深。在 Scala 中,事情往往有点嵌套。

普通的 Scala 用户是否有他们坚持的特定风格?为了[外星人]约定,我只是愚蠢地将单行案例类放在自己的文件中吗?有什么建议吗?

【问题讨论】:

标签: scala


【解决方案1】:

在一个文件中包含多个类和对象在 Scala 中被认为是好的形式,只要这些类紧密相关。

虽然没有必要,但方法返回的类型——在特征、类或对象上声明的命名函数——应该被声明为非私有方法。在: 之后需要有空格,但在它之前不能。

//  methods declared on a class, trait or object
def length: Int = ...
def multiply(other: Foo): Foo = ...

def hypotenuse(a: Double, b: Double): Double = {
  //  function inside a method, so effectively private
  def square(x: Double) = x * x

  math.sqrt(square(a) + square(b))
}

关键字和括号之间应该有空格,但方法名和后面的括号之间不能用点表示法。对于运算符表示法,似乎没有可接受的括号样式 - 或者何时使用该表示法,但在这种表示法中,非字母数字方法周围应有空格。

//  keywords
if (foo) ...

//  dot notation
foo.doSomething(bar)

//  operator notation
foo doSomething bar
foo + bar

在特殊情况下,当使用+ 连接字符串时,推荐的样式是不要在其周围使用空格。例如:

//  concatenate strings
println("Name: "+person.name+"\tAge: "+person.age)

可以是单行的声明应该是单行的,除非嵌套不明显。

//  one-liners
lazy val foo = calculateFoo
def square(x: Int) = x * x

不需要参数且没有副作用的方法应该不带括号使用,Java 方法除外,它们应该带括号使用。带有副作用的无参数方法应该与括号一起使用。

//  without side-effects
val x = foo.length
val y = bar.coefficient

//  with side-effects
foo.reverse()

包含单个表达式的声明不应包含在花括号内,除非其他语法考虑使之成为不可能。可以接受将表达式括在括号中以启用多行表达式,但我很少看到这种用法。

//  single-line expression
def sum(list: List[Int]): Int = if (!list.isEmpty) list reduceLeft (_ + _) else 0

//  multi-line expression
val sum = (
  getItems
  reduceLeft (_ + _)
)

在理解方面,保持生成器和条件垂直对齐似乎是一种公认​​的风格。至于yield,我看到它既与for对齐,又缩进。

//  for-comprehensions
val squares =
  for (x <- numbers)
    yield x * x

// Curly brackets-style identation
val cells = for {
  x <- columns
  y <- rows
  if x != y
} yield Cell(x, y)

// Parameter-style identation
val cells = for (x <- columns;
                 y <- rows;
                 if x != y)
            yield Cell(x, y)

垂直对齐类声明的参数也是公认的风格。

说到缩进,两个空格是公认的约定。

大括号应从声明的同一行开始,并与该行垂直对齐。

//  another example
def factorial(n: Int): Int = {
  def fact(n: Int, acc: Int): Int = n match {
    case 0 => acc
    case x => fact(x - 1, x * acc)
  }

  fact(n, 1)
}

对于过程——返回类型为Unit的函数——,预期的样式应该是省略方法的类型和等号:

//  procedures
def complain {
  println("Oh, no!")
}

有些人认为这种风格容易出错,但是,因为错过等号会将返回 Unit 以外的内容的函数更改为过程。

标识符以驼峰形式编写(例如:identifiersHaveHumps),就像在 Java 中一样。对于字段、方法参数、局部变量和函数的名称,以小写字母开头。对于类、特征和类型,以大写字母开头。

与 Java 约定不同的是常量名称。在 Scala 中,惯例是使用以大写字母开头的标准驼峰式大小写。例如Pi 而不是PI、XOffset 而不是X_OFFSET。任何单例通常都遵循此规则。对于大小写匹配,以这种方式表示常量和单例具有实际意义:

import scala.Math.Pi

val pi = Pi // this identifier will be shadowed by the identifier in the function below

def isPi(n: Double): Boolean = n match {
  case Pi => println("I got a true Pi."); true
  case pi => println("I got "+pi+" and bounded it to an identifier named pi."); false
}

包名以小写字母开头。当在 import 语句中区分什么是包和什么不是包时,这特别有用。在前面的示例中,Math 不是包(它是单例),因为它以大写字母开头。

不推荐使用下划线字符 --_ --,因为该字符在 Scala 中有许多特殊含义。这些标识符规则可以在 Odersky, Spoon & Venners 的 Programming in Scala 的第 141 和 142 页上找到。

目前,我不记得其他情况,但请随时要求澄清具体问题。其中一些规则是明确规定的,另一些则更多是社区共识。我试图忽略我自己的偏好,但我可能失败了。

更重要的是,也许实际上并没有太多统一的约定。原因之一可能是 Scala 吸引了来自许多不同背景的人,例如函数式语言专家、Java 程序员和 Web 2.0 爱好者。

【讨论】:

  • 实际上,我认为“省略等号”样式是 less 容易出错的,因为它实际上是显式注释 Unit 的简写。意图非常明确,比显式注释要简洁得多。值得注意的是,all 副作用方法应该用括号声明,特别是包括 arity-1 的那些。无括号方法用于纯函数和逻辑属性访问器。
  • 好的,我会更正答案。事实上,我会让它成为社区。但是,有一些关于使无参数方法和函数在所有情况下都使用括号的讨论。
  • 事实上,Scala 编程一书建议,如果方法没有参数并且没有副作用(例如,当访问对象的状态)。因此,像println() 这样的调用应该仍然有括号,但queue.sizearray.length 没有(参见统一访问原则-en.wikipedia.org/wiki/Uniform_access_principle)。后一个例子是java中的queue.size()array.length,不尊重这个原则。
  • 一个很好的答案,可以用更多的例子来做。你介意我加一些吗?
  • @nafg 我不知道我的意图是什么,但我当然不同意所说的,所以我会解决它。
【解决方案2】:

现在有一个完整的 Scala 风格指南 proposed to the community。它甚至还不是官方的,但它是(据我所知)社区接受的公约的唯一编纂。

【讨论】:

【解决方案3】:

现在 Scala Style Guide 可用。它不是 100% 官方的(位于“Community-driven documentation for Scala”网站),但似乎是 Scala 最标准的样式指南。

【讨论】:

    【解决方案4】:

    这是一个非常重要的问题。一般来说,Scala 风格似乎只是通过与 Scala 社区的其他成员一起闲逛、阅读 Scala 源代码等来获得。这对于该语言的新手来说并不是很有帮助,但它确实表明某种事实上的标准 确实存在(由大众的智慧选择)。我目前正在为 Scala 编写一个完全实现的样式指南,其中记录了社区选择的约定和最佳实践。但是,a) 它还没有完成,并且 b) 我还不确定我是否会被允许发布它(我正在写它是为了工作)。

    回答你的第二个问题(有点):一般来说,每个类/特征/对象都应该根据 Java 命名约定获得自己的文件。然而,在你有很多类共享一个共同概念的情况下,有时将它们全部放在同一个文件中是最简单的(无论是短期还是长期)。执行此操作时,文件名应以小写字母(仍为驼峰式)开头,并描述该共享概念。

    【讨论】:

    • 请在我的回答中指出任何错误。我不想传播错误的风格信息——我们已经足够分散了。
    【解决方案5】:

    我并不真正关心许多 Scala 编码人员使用的典型风格,所以我只是应用在 C#、Java 或尤其是 JavaScript 中使用的相同标准。

    Scala 可以非常具有表现力,但使用不熟悉的格式会增加您的入门门槛。特别是考虑到内部的DSLs,它不可能有一个“标准”。

    所以,我说要尽一切努力使您的代码对您和您的团队更具可读性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-02-20
      • 2017-11-30
      • 2021-12-17
      • 1970-01-01
      • 1970-01-01
      • 2017-11-26
      • 1970-01-01
      相关资源
      最近更新 更多