Scala风格的元素?

我一天写C#。 我所做的每件事都通过微软的代码分析和静态分析工具,所以我的C#有一个非常规则的结构和布局。 很明显,我用某种风格编写代码。 这是部分的,因为我没有select(如果我错过了逗号之前的空格,它将不会被编译),但是定期查看代码,知道在哪里寻找东西等也是很好的。

在周末我正在进入斯卡拉。 看看Scala API和Lift web框架的源代码,我很难看到任何标准化的风格。 例如,跳到我身上的一件事就是每个类缺less一个单独的文件。 另一个例子是与括号和括号不一致。

据我所知,可能有几个原因促成了这一点:首先,开源(或爱好)代码确保一个明显的方法没有完全logging是不是优先事项。 其次,案例类将20行的类声明切成一行。 第三,C#是一个非常“平淡”的语言:除非是一个复杂的LINQ语句,嵌套的parens,括号和括号的数量并不那么深。 在斯卡拉,事情往往会有一点嵌套。

常规的Scala用户有他们坚持的特定风格吗? 为了外国人的惯例,我只是把自己的文件放在一个单行的案例中去做傻事? 有小费吗?

在一个文件中有多个类和对象在Scala中被认为是很好的forms,只要类是紧密相关的。

虽然不是必要的,但方法返回的types(在特征,类或对象上声明的命名函数)预计将为非私有方法声明。 预期之后的空间,但不是之前。

 // 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 

例外情况下,当使用+连接string时,build议的样式不要在其周围使用空格。 例如:

 // 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() 

包含单个expression式的声明不应被包含在大括号内,除非其他语法考虑使得这是不可能的。 在括号内包括一个expression式来启用多行expression式是可以接受的,但是我没有看到使用它。

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

为了理解,保持生成器和条件垂直alignment似乎是一个公认的风格。 至于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) 

垂直alignment类声明的参数也是可接受的样式。

说到缩进,两个空格是公认的惯例。

花括号预计从声明的同一行开始,并且自行结束与该行垂直alignment。

 // 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) } 

对于过程 – 返回types为Unit函数,预期的样式应该是忽略方法的types和等号:

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

有些人认为这种风格很容易出错,但是由于错过了等号就会改变一个返回除Unit之外的东西的function。

标识符是用骆驼大写的(例如: identifiersHaveHumps ),就像在Java中一样。 对于字段名称,方法参数,局部variables和函数,以小写字母开头。 对于课程,特征和types,以大写字母开头。

离开Java约定是常量名称。 在斯卡拉,练习是使用标准的骆驼大写字母开头。 例如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不是一个包(它是一个单例),因为它以大写字母开头。

不build议使用下划线字符 – _ – ,因为该字符在Scala中有许多特殊的含义。 这些标识符的规则可以在Odersky,Spoon&Venners的Scala编程的第141和142页find。

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

更重要的是,也许,这并不是一个统一的约定。 其中一个原因可能是Scala吸引了许多不同背景的人,比如function语言专家,Java程序员和Web 2.0爱好者。

现在已经有一个完整的Scala风格指南,已经提交给社区 。 它甚至不是官方的,但它是唯一的(据我所知)社区接受的公约的编纂。

  • PDF
  • 文本

现在斯卡拉风格指南可用。 这不是100%正式(位于“ Scala社区驱动的文档 ”网站上),但似乎是Scala最标准的样式指南。

这是一个非常重要的问题。 一般来说,斯卡拉风格似乎只是通过与Scala社区的其他成员进行交stream,阅读Scala源代码等来获得。这对于新手来说并不是很有帮助,但它确实表明某种事实上的标准确实存在(如群众的智慧所选)。 我目前正在为Scala编写一个完全实现的风格指南,这个指南logging了社区select的约定和最佳实践。 但是,a)还没有完成,b)我还不确定是否允许发布它(我正在写它的工作)。

要回答你的第二个问题(一般来说):一般来说,每个class / trait / object应该根据Java命名约定得到自己的文件。 但是,如果你有很多课程共享一个共同的概念,有时最简单的(短期和长期)把它们放在同一个文件中。 当你这样做的时候,文件的名字应该以小写字母开头(仍然是camelCase),并且描述这个共享的概念。

我并不关心许多Scala编程人员使用的典型风格,所以我只使用与C#,Java或尤其是JavaScript相同的标准。

斯卡拉可以非常有performance力,但使用不熟悉的格式将增加您的进入壁垒。 特别是考虑内部的DSL ,这不可能有一个“标准”。

所以,我说要做任何事情使你的代码对你和你的团队更具可读性。