Tener múltiples clases y objetos dentro de un solo archivo se considera una buena forma en Scala, siempre que las clases estén estrechamente relacionadas.
Aunque no es necesario, se espera que el tipo devuelto por un método (una función nombrada declarada en un rasgo, clase u objeto) se declare para métodos no privados. Se esperan espacios después de :
, pero no antes. Se espera que
// 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))
}
espacios entre las palabras clave y los paréntesis, pero no entre un nombre de método y el siguiente paréntesis, en la notación de punto. Para la notación del operador, no parece haber un estilo aceptado con respecto a los paréntesis, o cuándo usar esa notación, para el caso, pero se esperan espacios alrededor de métodos no alfanuméricos en dicha notación.
// keywords
if (foo) ...
// dot notation
foo.doSomething(bar)
// operator notation
foo doSomething bar
foo + bar
Excepcionalmente, cuando la concatenación de cadenas con +
, el estilo es recomendable no utilizar espacios a su alrededor. Por ejemplo:
// concatenate strings
println("Name: "+person.name+"\tAge: "+person.age)
Declaraciones que pueden ser de una sola línea se espera que sean de una sola línea, a menos que la anidación no es obvia.
// one-liners
lazy val foo = calculateFoo
def square(x: Int) = x * x
métodos que no esperaría parámetros, y no tienen efectos secundarios, se supone que deben ser utilizados sin paréntesis, a excepción de los métodos de Java, que se espera para ser utilizado con paréntesis. Se supone que los métodos sin parámetros con efectos secundarios se usan con paréntesis. Se espera que
// without side-effects
val x = foo.length
val y = bar.coefficient
// with side-effects
foo.reverse()
Las declaraciones que contiene una sola expresión no debe ser encerrado dentro de llaves a menos que otras consideraciones sintácticas hacen eso imposible. Se acepta el encerrar una expresión entre paréntesis para habilitar expresiones de varias líneas, pero he visto poco uso de eso.
// single-line expression
def sum(list: List[Int]): Int = if (!list.isEmpty) list reduceLeft (_ + _) else 0
// multi-line expression
val sum = (
getItems
reduceLeft (_ + _)
)
En-comprensiones para mantener, generadores y condiciones verticalmente alineados parece ser un estilo aceptado. En cuanto a yield
, lo he visto alineado con for
y sangrado.
// 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)
También se acepta el estilo para alinear verticalmente los parámetros de una declaración de clase.
Hablando de sangría, dos espacios es la convención aceptada.
Se espera que las llaves se inicien en la misma línea de la declaración y terminen alineadas verticalmente con esa línea por sí mismo.
// 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)
}
Para los procedimientos de - funciones cuyo tipo de retorno es Unit
-, el estilo esperado se suponía que había que dejar de lado el tipo del método y el signo igual:
// procedures
def complain {
println("Oh, no!")
}
Algunas personas piensan Sin embargo, este estilo es propenso a errores, ya que un signo igual perdido no cambiará una función que devuelve algo que no sea Unit
en un procedimiento.
Los identificadores están escritos en camel case (p. Ej .: identifiersHaveHumps
), como en Java. Para nombres de campos, parámetros de métodos, variables locales y funciones, comience con una letra minúscula. Para clases, rasgos y tipos, comience con una letra mayúscula.
Saliendo de la convención de Java son nombres constantes. En Scala, la práctica es usar una caja de camello estándar que comience con una letra mayúscula. Por ejemplo, Pi
y no PI
, XOffset y no X_OFFSET
. Esta regla generalmente es seguida por cualquier singleton. Tener unas constantes y únicos pueden representar de esta manera tiene una consecuencia práctica, para el caso de los partidos:
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
}
Los nombres de paquetes se escriben comenzando con una letra minúscula. Esto es particularmente útil cuando se distingue en un extracto de importación qué es un paquete y qué no. En el ejemplo anterior, Math
no es un paquete (es un singleton), ya que comienza con una letra mayúscula.
No se recomienda el uso del carácter de subrayado - _
-, ya que ese carácter tiene muchos significados especiales en Scala. Estas reglas para identificadores se pueden encontrar en las páginas 141 y 142 de Programación en Scala, por Odersky, Spoon & Venners.
En este momento, no puedo recordar otras situaciones, pero no dude en pedir aclaraciones sobre puntos específicos. Algunas de estas reglas fueron explícitamente establecidas, otras son un consenso de la comunidad. Traté de dejar de lado mis propias preferencias, pero puede haber fallado.
Más importante aún, quizás no exista realmente una gran convención unificada. Una de las razones puede ser que Scala atraiga a personas de diferentes orígenes, como expertos en lenguaje funcional, programadores de Java y entusiastas de la web 2.0.
El Sr. Odersky dio una conferencia magistral en Scala Days 2013 en 'Scala with Style' - http://www.parleys.com/play/51c1994ae4b0d38b54f4621b/chapter0/about –