Scala стили кодирования и соглашения?

Я думаю, что 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
  }

Если методы растут, читать код становится очень больно, я не могу сопоставить фигурные скобки, не могу свернуть метод в IDE. Существуют ли какие-либо соглашения по кодированию Scala? Я чувствую, что это слишком гибко, чтобы выразить простой метод:

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

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

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

6 ответов

Решение

"Если метод растет, становится очень больно читать код". Я думаю, что часть ответа заключается в том, что методы не должны расти. Функциональный стиль программирования состоит в том, чтобы иметь много маленьких методов. Метод вычисления уже на большой стороне.

Чтобы ответить на более общие вопросы о руководствах по стилю для программирования Scala: Вот типичный пример.

Вот ссылка на Руководство по стилю Scala.


В разделе "Фигурные скобки" говорится:

Фигурные скобки:

Фигурные скобки должны быть опущены в случаях, когда структура управления представляет чисто функциональную операцию, а все ветви структуры управления (относящиеся к if / else) являются однострочными выражениями. Помните следующие рекомендации:

  • if - опустить фигурные скобки, если у вас есть предложение else. В противном случае заключите содержимое в фигурные скобки, даже если содержимое состоит из одной строки.

  • while - Никогда не опускайте скобки (пока нельзя использовать чисто функциональный способ).

  • for - опустить скобки, если у вас есть предложение yield. В противном случае, окружите содержимое фигурными скобками, даже если содержимое состоит из одной строки.

  • case - опустить фигурные скобки, если выражение case ts в одной строке. В противном случае используйте ясные фигурные скобки (даже если они не требуются синтаксическому анализатору).

    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!")
    }
    

Я хочу, чтобы люди следовали этому руководству по стилю:(


Обратите внимание, что я не согласен с "опустить брекеты, если if имеет else пункт "часть. Я бы предпочел видеть код, подобный этому:

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

Да это так. Например, http://davetron5000.github.com/scala-style/index.html

Конкретный пример, который вы цитируете, может выглядеть сложным, потому что он использует кеш для запоминания результатов. Если вы удалите памятку, метод уменьшится до:

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

который, я думаю, совсем не сложен.

Вот слово самого человека, который написал scala, и до сих пор является основным разработчиком этого языка.

Источник: Принципы функционального программирования в Scala, автор Martin Odersky

Вам также предлагается пройти его курс прямо сейчас или перейти по следующей ссылке предложения [1]

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

Справочник по стилю Scala

На этой странице вы можете найти список распространенных проблем, которые мы обнаружили при просмотре некоторых материалов.

Некоторые проблемы со стилем могут быть обнаружены с помощью автоматической проверки стиля, которую мы также используем для процесса оценки. Проверка стиля, основанная на Scalastyle, может быть выполнена локально в sbt, запустив задачу styleCheck.

Общие проблемы

1 Избегайте кастов и типовых тестов

Никогда не используйте isInstanceOf или asInstanceOf - всегда есть лучшее решение, как для заданий, так и для любого реального проекта Scala. Если вы захотите использовать приведение, сделайте шаг назад и подумайте, чего вы хотите достичь. Перечитайте инструкции по назначению и посмотрите на соответствующие видео лекции.

2 отступ

Убедитесь, что ваш код имеет правильные отступы, он станет намного более читабельным.

Это может показаться тривиальным и не очень актуальным для наших упражнений, но представьте, что в будущем вы станете частью команды, работающей над теми же файлами с другими программистами: очень важно, чтобы все соблюдали правила стиля, чтобы сохранить код здоровым.

Если ваш редактор не выполняет отступы так, как вы хотели бы, вы должны выяснить, как изменить его настройки. В Scala стандартом является отступ с использованием 2 пробелов (без табуляции).

3 строки длины и пробелы

Убедитесь, что строки не слишком длинные, иначе ваш код будет очень трудно читать. Вместо того, чтобы писать очень длинные строки, введите некоторые привязки локальных значений. Использование пробелов равномерно делает ваш код более читабельным.

Пример (длинная строка, пропущенные пробелы):

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

Лучше:

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

Еще лучше (см. № 4 и № 6 ниже):

val newAccu =

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

4 Используйте локальные значения для упрощения сложных выражений

При написании кода в функциональном стиле методы часто реализуются как комбинация вызовов функций. Если такое комбинированное выражение становится слишком большим, код может стать трудным для понимания.

В таких случаях лучше сохранить некоторые аргументы в локальном значении, прежде чем передавать их в функцию (см. #3 выше). Убедитесь, что локальное значение имеет значимое имя (см. № 5 ниже)!

5 Выберите значимые имена для методов и значений

Имена методов, полей и значений должны быть тщательно подобраны, чтобы исходный код был легким для понимания. Имя метода должно прояснить, что делает метод. Нет, темп никогда не бывает хорошим именем:-)

Несколько невероятных примеров:

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 общих выражений

Вы должны избегать ненужных вызовов интенсивных методов. Например

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

дважды вызывает метод this.findMin. Если каждый вызов является дорогостоящим (например, должен проходить через всю структуру данных) и не имеет побочного эффекта, вы можете сохранить его, введя привязку локального значения:

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

Это становится еще более важным, если функция вызывается рекурсивно: в этом случае метод вызывается не только несколько раз, но и экспоненциально.

7 Не копируйте и не вставляйте код!

Копирование-вставка кода всегда предупреждает о плохом стиле! Есть много недостатков:

Код длиннее, для его понимания требуется больше времени. Если две части не идентичны, но очень похожи, очень трудно определить различия (см. Пример ниже). Сохранение двух копий и обеспечение их синхронизации синхронизированы - это очень ошибочно -prone Умножается объем работ, необходимых для внесения изменений в код. Вы должны разбивать общие части на отдельные методы, а не копировать код. Пример (см. Также № 3 выше для другого примера):

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 не требует точек с запятой

Точки с запятой в Scala требуются только при написании нескольких операторов в одной строке. Следует избегать записи ненужных точек с запятой, например:

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

9 Не отправляйте код с "печатными" заявлениями

Вы должны очистить свой код и удалить все операторы print или println перед его отправкой. То же самое будет применяться, когда вы работаете в компании и создаете код, который используется в производстве: окончательный код не должен содержать операторов отладки.

10 Избегайте использования возврата

В Scala вам часто не нужно использовать явные возвраты, потому что управляющие структуры, такие как if, являются выражениями. Например, в

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

операторы return могут быть просто отброшены.

11 Избегайте изменяемых локальных переменных

Поскольку это курс по функциональному программированию, мы хотим, чтобы вы привыкли писать код в чисто функциональном стиле, без использования побочных операций. Вы можете часто переписывать код, который использует изменяемые локальные переменные, для кодирования с помощью вспомогательных функций, которые используют аккумуляторы. Вместо:

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
}

предпочитают:

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 Исключите избыточные выражения "если"

Вместо

if (cond) true else false

ты можешь просто написать

cond

(Аналогично для случая с негаитве).

Другие проблемы с дизайном? Пожалуйста, отправляйте сообщения на форум, используя style или styleChecktags, и мы дополним это руководство по стилю предложениями.

Да, это немного поздно, но я хотел опубликовать это, поскольку он отражает реальный подход, один для "глобальной читаемости и ремонтопригодности", и включает в себя информацию от участников Apache Spark: Databricks Scala Style Guide

На этом сайте есть много соглашений http://docs.scala-lang.org/style/

Другие вопросы по тегам