/cis-scala

MIPT CIS Scala course

Primary LanguageScala

Курс по Scala кафедры корпоративных информационных систем МФТИ

Контакты

  • Канал в slack (весна 2021): #scala_spr2021
  • Telegram для контактов: @valentiay
  • Почта для домашек: valentiay@yandex.ru

Запуск проекта и тестирование домашних заданий

Для сборки проекта используется sbt. Ниже несколько полезных команд.

# Перезагрузить конфигурацию проекта, если *.sbt-файлы, описывающие билд изменились
sbt reload

# Собрать проект (без тестов)
sbt compile

# Запустить конкретный Main-класс
sbt "runMain seminars.seminar1.HelloWorld1"

# Запустить все тесты
sbt test

# Запустить тесты для конкретного пакета (например, пакета с тестами на 1 дз)
sbt testOnly homeworks.homework1.*

# Запустить тесты на конкретный клас (например, на первую задачу первого дз)
sbt testOnly homeworks.homework1.task1Test

Также слайды и тесты можно запустить с помощью Intellij Idea с scala-плагином.

Линтер

В проекте подключен линтер WartRemover. При использовании одного из инструментов ниже, проект не соберется. В большинстве случаев нужно отрефакторить код так, чтобы этот инструмент не использовался. Отключить ошибку можно аннотацией @SuppressWarnings(Array("org.wartremover.warts.All")), перед этим лучше уточнить в чате, стоит ли так делать. Если с рефакторингом возникают проблемы, тоже можно попросить помощи в чате.

AsInstanceOf

Почти всегда тип можно привести без использования кастов. Для чисел можно использовать встроенные методы .toChar, .toInt, toLong и т.п.

Для апкаста можно указывать типы в функциях, например так:

import scala.util.Random

def nextLong: Long = Random.nextInt

При работе с эффектами можно использовать метод функтора .widen:

import cats.effect.IO
import cats.syntax.applicative._
import cats.syntax.functor._

val a: IO[Option[String]] = None.pure[IO].widen

Вместо даункастов нужно использовать паттерн-матчинг.

.asInstanceOf может использоваться для некоторых оптимизаций, например, newtype.

MutableDataStructures

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

Null

Использование null ведет к непредсказуемым исключениям. Вместо него нужно использовать Option.

Return

При использовании return появляются неожиданные точки выхода из программы, что снижает читаемость кода. Значения должны возвращаться в конце блока.

Throw

Использование исключений, как и return дает неожиданные точки выхода. Вместо исключений нужно использовать Option, Either или средства библиотеки эффектов.

Var

Аналогично MutableDataStructures

While

Чаще всего ведет к использованию изменяемых переменных и коллекций. Вместо while нужно использовать хвостовую рекурсию или .foldLeft и подобные.

Пример кода, компиляция которого упадет со всеми возможными ошибками линтера

def foo: Int = {
  val as = scala.collection.mutable.ListBuffer.empty[Int]
  as += 1
  as += null.asInstanceOf[Int]
  as += 2

  var i = 0
  while (i < as.length) {
   val a = as(i)
    if (a == null) throw new NullPointerException("Unexpected null!")
    if (a % 2 == 0) return a
    i += 1
  }
  0
}