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 }

Ответы

Ответ 1

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

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

Ответ 2

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


В разделе Curly Braces говорится:

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

Кудрявые фигурные скобки должны быть опущены в случаи, когда контрольная структура представляет собой чисто функциональный эксплуатации и всех ветвей структуры управления (относящейся к 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
  }
}

Ответ 4

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

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

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

Ответ 5

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

Источник: Принципы функционального программирования в Scala Мартин Одерски

вам также предлагается принять его курс сейчас или следующее предложение ссылка [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 Выберите значащие имена для методов и значений

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

Несколько улучшенных примеров:

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 Dont Copy-Paste Code!

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

Код длиннее, для его понимания требуется больше времени Если две части не идентичны, но очень похожи, очень трудно определить различия (см. Пример ниже) Поддержание двух копий и обеспечение их синхронизации очень подвержены ошибкам Объем работы, необходимый для внесения изменений в код, умножается Вы должны разделить общие части на отдельные методы, а не на копирование кода. Пример (см. Также № 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"

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

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

В 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

(Аналогично для случая negaitve).

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