Методы: def, параметры и возврат

Метод в Scala — это именованный кусочек логики, и описать его можно поразительно коротко.

«Хороший метод делает одно дело и возвращает результат — без сюрпризов и побочных эффектов.»

Метод объявляется ключевым словом def. После имени в скобках идут параметры с типами, затем — тип возвращаемого значения, и после = тело.

def square(x: Int): Int =
  x * x

def greet(name: String): String =
  s"Привет, $name!"

println(square(5))       // 25
println(greet("Лена"))   // Привет, Лена!

Тело — это выражение

Ключевая идея: в Scala тело метода — это выражение, которое возвращает значение. Не нужно писать return — результатом становится последнее вычисленное выражение. return в Scala избегают.

def max(a: Int, b: Int): Int =
  if a > b then a else b   // if — это выражение, оно возвращает значение

Тип возврата можно не писать

Для простых методов Scala выведет тип сама, но для публичных методов тип возврата принято указывать явно — как контракт.

def double(x: Int) = x * 2   // тип выведется как Int
val r = double(21)           // 42

Несколько параметров и блок в теле

def describe(name: String, age: Int): String =
  val status = if age >= 18 then "взрослый" else "ребёнок"
  s"$name — $status ($age лет)"

println(describe("Иван", 30))

Та же идея на Python ▶

# Методы как функции на Python
def square(x):
    return x * x

def greet(name):
    return f"Привет, {name}!"

def describe(name, age):
    status = "взрослый" if age >= 18 else "ребёнок"
    return f"{name} — {status} ({age} лет)"

print(square(5))
print(greet("Лена"))
print(describe("Иван", 30))
def square ( x : Int ) : Int =  x * x
     ^      ^   ^       ^      ^
   имя   параметр тип  возврат тело

Как работает под капотом (JVM)

Метод Scala компилируется в обычный метод JVM с теми же типами параметров и возврата. Поскольку тело — выражение, компилятор просто берёт его значение как возвращаемое. Отсутствие return ничего не меняет для JVM: под капотом всё равно генерируется инструкция возврата с последним значением. Явный тип возврата помогает компилятору проверять корректность и ускоряет компиляцию рекурсивных методов.

Частые ошибки

  • Писать return. В Scala это лишнее и иногда меняет поведение в неожиданную сторону. Полагайтесь на последнее выражение.
  • Забыть = перед телом. Без него метод считается возвращающим Unit, и результат теряется.
  • Не указать тип возврата у рекурсивного метода. Тогда вывод типов не справится — компилятор потребует явный тип.

Best practices

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

Методы как кирпичики мышления

В Scala метод — это не просто способ сгруппировать инструкции, а единица смысла. Поскольку тело метода является выражением, метод естественно описывает «как из входа получить выход», а не «какие шаги выполнить». Это сдвигает фокус с императивной последовательности действий на декларативное описание результата. Привыкнув к этому, вы начнёте дробить логику на маленькие чистые методы, каждый из которых отвечает на один вопрос.

Чистота методов — отдельная ценность. Метод, результат которого зависит только от аргументов и который не трогает внешний мир, легко тестировать: дал вход, проверил выход. Его легко переиспользовать, потому что он не тащит за собой скрытый контекст. И его легко рассуждать о корректности, потому что он не может неожиданно повлиять на остальную программу. Стремление к таким методам — основа здорового кода на Scala.

Со временем вы заметите, что хорошо названный метод документирует код лучше любого комментария. Имя вроде isEligibleForDiscount сразу объясняет намерение, а его чистое тело гарантирует, что результат зависит только от входа. Привычка дробить логику на такие самоописывающие методы делает программу читаемой сверху вниз, как связный текст, а не как набор разрозненных инструкций.

Итоги. def объявляет метод, тело — это выражение (без return), тип возврата выводится, но для публичного API его указывают. Дальше — функции как значения.

Проверьте себя
1. Что является результатом метода в Scala, если нет return?
AВсегда Unit
BЗначение последнего выражения в теле
CЗначение первого выражения
Dnull
2. Что произойдёт, если забыть = перед телом метода: def f(x: Int) { x * 2 }?
AМетод вернёт x*2
BМетод будет иметь тип Unit и не вернёт результат
CОшибка: скобки запрещены
DМетод станет приватным