2010-09-15 8 views
17

Creo que Scala va demasiado lejos de la simplicidad, como su sintaxis. Por ejemplo Martin Odersky escribió el método en su libro:¿Estilos y convenciones de codificación Scala?

def calculate(s: String): Int = 
    if (cache.contains(s)) 
    cache(s) 
    else { 
    val acc = new ChecksumAccumulator 
    for (c <- s) 
     acc.add(c.toByte) 
    val cs = acc.checksum() 
    cache += (s -> cs) 
    cs 
    } 

Si los métodos crece, se hace muy doloroso leer el código, no puedo coincidir con las llaves, no puedo doblar el método en el IDE. ¿Hay alguna convención de codificación Scala? Siento que es demasiado flexible para expresar un método sencillo:

def add(b: Byte): Unit = { 
    sum += b 
} 

def add(b: Byte): Unit = sum += b 

def add(b: Byte) { sum += b } 
+0

¿Qué le estas convenciones de codificación intentar hacer? – wheaties

+7

Debido a que hay demasiadas formas de expresar una línea simple de código en Scala, las convenciones de codificación ayudarían a formalizar códigos dentro de equipos o comunidades. – Sawyer

+0

¿Cómo podría ayudar una convención en su segundo ejemplo de código a su primer ejemplo de legibilidad? – Debilski

Respuesta

35

"Si el método crece se hace muy doloroso leer el código". Creo que parte de la respuesta es que los métodos no deberían crecer. El estilo de programación funcional es tener muchos métodos pequeños. El método de cálculo ya está en el lado grande.

Para responder a las preguntas más generales sobre las guías de estilo para la programación de Scala: Aquí hay un representative example.

+0

¡Esto es especialmente fácil porque puede definir métodos dentro de métodos! Una excelente manera de romper tu código. Y mucho más agradable que los métodos de acompañamiento privado para funciones recursivas como en Java. – schmmd

4

El ejemplo particular que se cita puede parecer compleja porque está utilizando una caché para memoize los resultados. Si se quita la memoization, el método de reducir a:

def calculate(s: String): Int = { 
    val acc = new ChecksumAccumulator 
    for (c <- s) 
     acc.add(c.toByte) 
    acc.checksum() 
} 

que creo, no es complejo en absoluto.

+0

Sus pestañas están en mal estado. – Det

24

Aquí hay un enlace al Scala Style Guide.


La sección Curly Los apoyos dice:

entre llaves:

entre llaves deben ser omitidos en casos en los que la estructura de control representa un puro- operación funcional y todas las ramas de la estructura de control (relevante para if/else) son expresiones de una sola línea. recuerde las siguientes directrices:

  • si - Omitir los apoyos si tiene una cláusula else. De lo contrario, rodee el contenido con llaves, incluso si el contenido es solo una línea.

  • while - Nunca omita las llaves (mientras que no se puede utilizar de manera totalmente funcional ).

  • for - Omita llaves si usted tiene una cláusula de rendimiento. De lo contrario, rodee el contenido con llaves, incluso si el contenido es solo una línea.

  • caso - Omita llaves si la expresión de caso es ts en una sola línea. De lo contrario, utilice llaves para claridad (aunque no sean requeridas por el analizador).

    val news = if (foo) 
        goodNews() 
    else 
        badNews() 
    
    if (foo) { 
        println("foo was true") 
    } 
    
    news match { 
        case "good" => println("Good news!") 
        case "bad" => println("Bad news!") 
    } 
    

deseo personas siguieron esta guía de estilo :(


Tenga en cuenta que no estoy de acuerdo con "Omitir los apoyos si if tiene un else cláusula" parte.Había prefiero ver el código como el siguiente:

def calculate(s: String): Int = { 
    if (cache.contains(s)) { 
    cache(s) 
    } else { 
    val acc = new ChecksumAccumulator 
    for (c <- s) { 
     acc.add(c.toByte) 
    } 
    val cs = acc.checksum() 
    cache += (s -> cs) 
    cs 
    } 
} 
+1

paréntesis ayuda a formatear los códigos, también me gustan tus estilos, tal vez solo vengo de Java. – Sawyer

+0

No sé por qué una convención exigiría una puntuación superflua. –

+0

@Randall: en el mundo Java lo hace, y por una buena razón: hace que el código sea más fácil de refactorizar, y de leer (en mi opinión). – missingfaktor

1

Aquí está la palabra del hombre que escribió scala, él mismo, y sigue siendo el principal implementador de este lenguaje.

Fuente: Principios de programación funcionales en Scala de Martin Odersky

también está invitado a tomar su curso ahora o la próxima oferta link [1]

========== =================

Guía de Estilo Scala Ayuda

en esta página usted puede encontrar una lista de los problemas comunes que hemos detectado mientras se mira en algunas presentaciones.

Algunos de los problemas de estilo pueden ser detectados por el corrector de estilo automático que también usamos para el proceso de clasificación. El verificador de estilo, que se basa en Scalastyle, se puede ejecutar localmente en sbt ejecutando la tarea styleCheck.

Problemas comunes

1 Evita yesos y Ensayos Tipo

Nunca use isInstanceOf o asInstanceOf - siempre hay una mejor solución, tanto para las asignaciones, y también para cualquier proyecto en el mundo real Scala. Si te apetece usar moldes, da un paso atrás y piensa en lo que intentas lograr. Vuelva a leer las instrucciones de asignación y tenga otra mirada a los videos de conferencia correspondientes.

2 sangría

Asegúrese de que el código es adecuadamente con sangría, se hace mucho más fácil de leer.

Esto puede parecer trivial y no muy relevante para nuestros ejercicios, pero imagine que en el futuro será parte de un equipo, trabajando en los mismos archivos con otros codificadores: es muy importante que todos respeten las reglas de estilo para mantener el código saludable.

Si su editor no realiza la sangría de la manera que le gustaría, debe descubrir cómo cambiar su configuración. En Scala, el estándar es sangría usando 2 espacios (sin pestañas).

3 longitud de línea y espacios en blanco

Asegúrese de que las líneas no son demasiado largos, de lo contrario su código es muy difícil de leer. En lugar de escribir líneas muy largas, introduzca algunas vinculaciones de valores locales. El uso de espacios en blanco hace que el código sea más legible.

Ejemplo (línea larga, espacios que faltan):

if(p(this.head))this.tail.filter0(p, accu.incl(this.head))else this.tail.filter0(p, accu) 

Mejor:

if (p(this.head)) 
    this.tail.filter0(p, accu.incl(this.head)) 
else 
    this.tail.filter0(p, accu) 

Incluso mejor (ver # 4 y # 6 a continuación):

val newAccu =

if (p(this.head)) accu.incl(this.head) 
    else accu 
this.tail.filter0(p, newAccu) 

4 Usar local Valores para simplificar expresiones complejas

Al escribir código en estilo funcional, los métodos a menudo se implementan como una combinación de llamadas a función. Si esa expresión combinada crece demasiado, el código puede ser difícil de entender.

En tales casos, es mejor almacenar algunos argumentos en un valor local antes de pasarlos a la función (ver n. ° 3 arriba). ¡Asegúrese de que el valor local tenga un nombre significativo (vea el # 5 a continuación)!

5 elegir los nombres significativos para los métodos y valores

Los nombres de métodos, campos y valores deben ser elegidos cuidadosamente para que el código fuente es fácil de entender. El nombre de un método debe aclarar lo que hace el método. No, la temperatura no es un buen nombre :-)

Algunos ejemplos mejorables:

val temp = sortFuntion0(list.head, tweet) // what does sortFunction0 do? 
def temp(first: TweetSet, second : TweetSet): TweetSet = ... 
def un(th: TweetSet,acc: TweetSet): TweetSet = ... 
val c = if (p(elem)) accu.incl(elem) else accu 
def loop(accu: Trending, current: TweetSet): Trending = ... 
def help(ch: Char, L2: List[Char], compteur: Int): (Char, Int) = ... 
def help2(L: List[(Char, Int)], L2: List[Char]): List[(Char, Int)] = ... 

6 subexpresiones comunes

usted debe evitar innecesarias invocaciones de métodos de computación intensiva. Por ejemplo

this.remove(this.findMin).ascending(t + this.findMin) 

invoca el método this.findMin dos veces. Si cada invocación es caro (por ejemplo, tiene que atravesar una estructura de datos entera) y no tiene un efecto secundario, puede guardar una por la introducción de un valor local de unión:

val min = this.findMin 
this.remove(min).ascending(t + min) 

Esto se vuelve aún más importante si la función se invoca de forma recursiva: en este caso, el método no solo se invoca varias veces, sino que también se multiplica exponencialmente.

7 ¡No copie y pegue el código!

¡Copiar y pegar el código siempre es una señal de advertencia para el mal estilo! Hay muchas desventajas:

El código es más largo, se necesita más tiempo para entenderlo Si las dos partes no son idénticos, pero muy similares, es muy difícil de encontrar las diferencias (véase el ejemplo siguiente) mantenimiento de dos copias y asegurarse de que permanecen sincronizadas es muy propenso a errores La cantidad de trabajo requerido para realizar cambios en el código se multiplica Debe factorizar partes comunes en métodos separados en lugar de copiar el código.Ejemplo (véase también el punto 3 anterior para otro ejemplo):

val googleTweets: TweetSet = TweetReader.allTweets.filter(tweet => 
    google.exists(word => tweet.text.contains(word))) 
val appleTweets: TweetSet = TweetReader.allTweets.filter(tweet => 
    apple.exists(word => tweet.text.contains(word))) 
This code is better written as follows: 

def tweetsMentioning(dictionary: List[String]): TweetSet = 
    TweetReader.allTweets.filter(tweet => 
    dictionary.exists(word => tweet.text.contains(word))) 

val googleTweets = tweetsMentioning(google) 
val appleTweets = tweetsMentioning(apple) 

8 Scala no requiere punto y coma

punto y coma en Scala solamente se requieren al escribir varias instrucciones en la misma línea. Escribiendo punto y coma innecesaria debe evitarse, por ejemplo:

def filter(p: Tweet => Boolean): TweetSet = filter0(p, new Empty); 

9 No presente Código con las declaraciones de “imprimir”

Usted debe limpiar su código y eliminar toda forma impresa o sentencias println antes de enviarla. Lo mismo se aplicará una vez que trabaje para una empresa y cree un código que se utilice en producción: el código final debe estar libre de instrucciones de depuración.

10 Evitar el uso de Retorno

En Scala, que a menudo no es necesario utilizar los rendimientos explícitos porque las estructuras de control, como si son expresiones. Por ejemplo, en

def factorial(n: Int): Int = { 
    if (n <= 0) return 1 
    else return (n * factorial(n-1)) 
} 

las declaraciones de devolución simplemente pueden soltarse.

11 Evitar las variables locales mutables

Dado que este es un curso de programación funcional, queremos que se acostumbra a escribir código en un estilo puramente funcional, sin necesidad de utilizar las operaciones de efectuar secundarios. A menudo puede reescribir el código que usa variables locales mutables para codificar con funciones auxiliares que toman acumuladores. En lugar de:

def fib(n: Int): Int = { 
    var a = 0 
    var b = 1 
    var i = 0 
    while (i < n) { 
    val prev_a = a 
    a = b 
    b = prev_a + b 
    i = i + 1 
    } 
    a 
} 

prefieren:

def fib(n: Int): Int = { 
    def fibIter(i: Int, a: Int, b: Int): Int = 
    if (i == n) a else fibIter(i+1, b, a+b) 
    fibIter(0, 0, 1) 
} 

12 Eliminar redundante “Si” Expresiones

en lugar de

if (cond) true else false 

simplemente hay que escribir

cond 

(De manera similar para el caso negativo).

¿Otros problemas de diseño? Publique en el foro usando el estilo o styleChecktags y aumentaremos esta guía de estilo con sugerencias.

+2

El punto # 5 es divertido, dado que el scaladoc está lleno de nombres de argumento llamados 'k',' g', 'p' y' z'. – jbx

+0

No me di cuenta cuando escribí que el creador del lenguaje mismo publicado aquí. Le gustaría leer sus publicaciones sobre Scala para ver más sobre las convenciones sintácticas. http://stackoverflow.com/a/3718851/1984636 – sivi

Cuestiones relacionadas