Avoir plusieurs classes et objets dans un seul fichier est considéré comme une bonne pratique en Scala, tant que les classes sont étroitement liées.
Bien que cela ne soit pas nécessaire, le type renvoyé par une méthode - une fonction nommée déclarée sur un trait, une classe ou un objet - doit être déclaré pour les méthodes non privées. Les espaces sont attendus après :
mais pas avant.
// 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))
}
Des espaces sont attendus entre les mots clés et les parenthèses, mais pas entre un nom de méthode et la parenthèse suivante, en notation point. Pour la notation des opérateurs, il ne semble pas y avoir de style accepté concernant les parenthèses - ou quand utiliser cette notation, d'ailleurs, mais des espaces sont attendus autour des méthodes non alphanumériques dans une telle notation.
// keywords
if (foo) ...
// dot notation
foo.doSomething(bar)
// operator notation
foo doSomething bar
foo + bar
Exceptionnellement, lors de la concaténation de chaînes de caractères avec +
le style recommandé est de ne pas utiliser d'espaces autour. Par exemple :
// concatenate strings
println("Name: "+person.name+"\tAge: "+person.age)
Les déclarations qui peuvent être d'une ligne sont censées être d'une ligne, à moins que l'imbrication ne soit pas évidente.
// one-liners
lazy val foo = calculateFoo
def square(x: Int) = x * x
Les méthodes qui n'attendent pas de paramètres et qui n'ont pas d'effets secondaires sont censées être utilisées sans parenthèses, à l'exception des méthodes Java, qui sont censées être utilisées avec des parenthèses. Les méthodes sans paramètres ayant des effets secondaires sont censées être utilisées avec des parenthèses.
// without side-effects
val x = foo.length
val y = bar.coefficient
// with side-effects
foo.reverse()
Les déclarations qui contiennent une seule expression ne doivent pas être placées entre accolades, à moins que d'autres considérations syntaxiques ne le rendent impossible. Le fait d'enfermer une expression entre parenthèses pour permettre des expressions sur plusieurs lignes est accepté, mais j'ai vu peu d'utilisation de cela.
// single-line expression
def sum(list: List[Int]): Int = if (!list.isEmpty) list reduceLeft (_ + _) else 0
// multi-line expression
val sum = (
getItems
reduceLeft (_ + _)
)
Dans les for-comprehensions, garder les générateurs et les conditions alignés verticalement semble être un style accepté. Comme pour les yield
Je l'ai vu à la fois aligné avec for
et en retrait.
// 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)
Il est également accepté d'aligner verticalement les paramètres d'une déclaration de classe.
En ce qui concerne l'indentation, deux espaces est la convention acceptée.
Les accolades sont censées commencer sur la même ligne de la déclaration et se terminer dans l'alignement vertical de cette ligne.
// 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)
}
Pour les procédures -- fonctions dont le type de retour est Unit
-- , le style attendu était censé laisser de côté le type de la méthode et le signe égal :
// procedures
def complain {
println("Oh, no!")
}
Certains pensent que ce style est source d'erreurs, cependant, car un signe égal oublié changera une fonction retournant autre chose que Unit
dans une procédure.
Les identifiants sont écrits en majuscules (ex : identifiersHaveHumps
), comme en Java. Pour les noms de champs, de paramètres de méthodes, de variables locales et de fonctions, commencez par une lettre minuscule. Pour les classes, les traits et les types, commencez par une lettre majuscule.
Les noms constants s'écartent de la convention Java. En Scala, la pratique est d'utiliser la casse standard en commençant par une lettre majuscule. Par exemple Pi
et non PI
, XOffset et non X_OFFSET
. Cette règle est généralement suivie par tout singleton. Le fait que les constantes et les singletons soient représentés de cette manière a une conséquence pratique, pour les correspondances de cas :
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
}
Les noms des paquets sont écrits en commençant par une lettre minuscule. Cela est particulièrement utile pour distinguer dans une déclaration d'importation ce qui est un paquetage et ce qui ne l'est pas. Dans l'exemple précédent, Math
n'est pas un paquet (c'est un singleton), car il commence par une lettre majuscule.
Utilisation du caractère de soulignement -- _
-- n'est pas recommandé, car ce caractère a de nombreuses significations spéciales en Scala. Ces règles pour les identificateurs se trouvent aux pages 141 et 142 de Programming in Scala, par Odersky, Spoon & Venners.
Pour l'instant, je ne me souviens pas d'autres situations, mais n'hésitez pas à demander des précisions sur des points spécifiques. Certaines de ces règles ont été explicitement énoncées, d'autres relèvent davantage d'un consensus de la communauté. J'ai essayé de laisser de côté mes propres préférences, mais j'ai peut-être échoué.
Plus important encore, peut-être, il n'y a tout simplement pas vraiment de convention unifiée. Cela peut s'expliquer par le fait que Scala attire des personnes venant d'horizons très différents, comme des spécialistes des langages fonctionnels, des programmeurs Java et des passionnés du Web 2.0.