Написание однострочных программ только в Scala 3
Scala 3 предлагает следующий способ определения программ, которые можно вызывать из командной строки:
добавление аннотации @main
к методу превращает его в точку входа исполняемой программы:
@main def hello() = println("Hello, World")
Для запуска программы достаточно сохранить эту строку кода в файле с именем, например, Hello.scala
(имя файла необязательно должно совпадать с именем метода) и запустить с помощью scala
:
$ scala Hello.scala
Hello, World
Аннотированный метод @main
может быть написан либо на верхнем уровне (как показано),
либо внутри статически доступного объекта.
В любом случае имя программы - это имя метода без каких-либо префиксов объектов.
Узнайте больше об аннотации @main
, прочитав следующие разделы или посмотрев это видео:
Аргументы командной строки
Метод @main
может обрабатывать аргументы командной строки с различными типами.
Например, данный метод @main
, который принимает параметры Int
, String
и дополнительные строковые параметры:
@main def happyBirthday(age: Int, name: String, others: String*) =
val suffix = (age % 100) match
case 11 | 12 | 13 => "th"
case _ => (age % 10) match
case 1 => "st"
case 2 => "nd"
case 3 => "rd"
case _ => "th"
val sb = StringBuilder(s"Happy $age$suffix birthday, $name")
for other <- others do sb.append(" and ").append(other)
println(sb.toString)
После компиляции кода создается основная программа с именем happyBirthday
, которая вызывается следующим образом:
$ scala happyBirthday 23 Lisa Peter
Happy 23rd Birthday, Lisa and Peter!
Как показано, метод @main
может иметь произвольное количество параметров.
Для каждого типа параметра должен существовать given экземпляр
класса типа scala.util.CommandLineParser.FromString
, который преобразует аргумент из String
в требуемый тип параметра.
Также, как показано, список параметров основного метода может заканчиваться повторяющимся параметром типа String*
,
который принимает все оставшиеся аргументы, указанные в командной строке.
Программа, реализованная с помощью метода @main
, проверяет,
что в командной строке достаточно аргументов для заполнения всех параметров,
и что строки аргументов могут быть преобразованы в требуемые типы.
Если проверка завершается неудачей, программа завершается с сообщением об ошибке:
$ scala happyBirthday 22
Illegal command line after first argument: more arguments expected
$ scala happyBirthday sixty Fred
Illegal command line: java.lang.NumberFormatException: For input string: "sixty"
Пользовательские типы как параметры
Как упоминалось выше, компилятор ищет заданный экземпляр класса типов scala.util.CommandLineParser.FromString
для типа аргумента. Например, предположим, что у вас есть собственный тип Color
,
который вы хотите использовать в качестве параметра.
Вы можете сделать это, как показано ниже:
enum Color:
case Red, Green, Blue
given ComamndLineParser.FromString[Color] with
def fromString(value: String): Color = Color.valueOf(value)
@main def run(color: Color): Unit =
println(s"The color is ${color.toString}")
Это работает одинаково для ваших собственных пользовательских типов в вашей программе, а также для типов, которые можно использовать из другой библиотеки.
Детали
Компилятор Scala генерирует программу из @main
метода f
следующим образом:
- он создает класс с именем
f
в пакете, где был найден метод@main
. - класс имеет статический метод
main
с обычной сигнатурой Javamain
метода: принимаетArray[String]
в качестве аргумента и возвращаетUnit
. - сгенерированный
main
метод вызывает методf
с аргументами, преобразованными с помощью методов в объектеscala.util.CommandLineParser.FromString
.
Например, приведенный выше метод happyBirthday
генерирует дополнительный код, эквивалентный следующему классу:
final class happyBirthday {
import scala.util.{CommandLineParser as CLP}
<static> def main(args: Array[String]): Unit =
try
happyBirthday(
CLP.parseArgument[Int](args, 0),
CLP.parseArgument[String](args, 1),
CLP.parseRemainingArguments[String](args, 2)*)
catch {
case error: CLP.ParseError => CLP.showError(error)
}
}
Примечание: В этом сгенерированном коде модификатор
<static>
выражает, чтоmain
метод генерируется как статический метод классаhappyBirthday
. Эта функция недоступна для пользовательских программ в Scala. Вместо неё обычные “статические” члены генерируются в Scala с использованиемobject
.
Обратная совместимость со Scala 2
@main
методы — это рекомендуемый способ создания программ, вызываемых из командной строки в Scala 3.
Они заменяют предыдущий подход, который заключался в создании object
, расширяющего класс App
:
Прежняя функциональность App
, основанная на “волшебном” DelayedInit trait
, больше недоступна.
App
все еще существует в ограниченной форме, но не поддерживает аргументы командной строки и будет объявлен устаревшим в будущем.
Если программам необходимо выполнять перекрестную сборку между Scala 2 и Scala 3,
вместо этого рекомендуется использовать object
с явным методом main
и одним аргументом Array[String]
:
object happyBirthday {
private def happyBirthday(age: Int, name: String, others: String*) = {
... // тоже, что и раньше
}
def main(args: Array[String]): Unit =
happyBirthday(args(0).toInt, args(1), args.drop(2).toIndexedSeq:_*)
}
обратите внимание, что здесь мы используем
:_*
для передачи переменного числа аргументов, который остается в Scala 3 для обратной совместимости.
Если вы поместите этот код в файл с именем happyBirthday.scala, то сможете скомпилировать его с scalac
и запустить с помощью scala
, как показывалось ранее:
$ scalac happyBirthday.scala
$ scala happyBirthday 23 Lisa Peter
Happy 23rd Birthday, Lisa and Peter!
Contributors to this page:
Contents
- Введение
- Возможности Scala
- Почему Scala 3?
- Почувствуй Scala
- Пример 'Hello, World!'
- REPL
- Переменные и типы данных
- Структуры управления
- Моделирование данных
- Методы
- Функции первого класса
- Одноэлементные объекты
- Коллекции
- Контекстные абстракции
- Верхнеуровневые определения
- Обзор
- Первый взгляд на типы
- Интерполяция строк
- Структуры управления
- Моделирование предметной области
- Инструменты
- Моделирование ООП
- Моделирование ФП
- Методы
- Особенности методов
- Main методы в Scala 3
- Обзор
- Функции
- Анонимные функции
- Параметры функции
- Eta расширение
- Функции высшего порядка
- Собственный map
- Создание метода, возвращающего функцию
- Обзор
- Пакеты и импорт
- Коллекции в Scala
- Типы коллекций
- Методы в коллекциях
- Обзор
- Функциональное программирование
- Что такое функциональное программирование?
- Неизменяемые значения
- Чистые функции
- Функции — это значения
- Функциональная обработка ошибок
- Обзор
- Типы и система типов
- Определение типов
- Параметризованные типы
- Пересечение типов
- Объединение типов
- Алгебраические типы данных
- Вариантность
- Непрозрачные типы
- Структурные типы
- Зависимые типы функций
- Другие типы
- Контекстные абстракции
- Методы расширения
- Параметры контекста
- Контекстные границы
- Given импорты
- Классы типов
- Многостороннее равенство
- Неявное преобразование типов
- Обзор
- Параллелизм
- Scala утилиты
- Сборка и тестирование проектов Scala с помощью Sbt
- Рабочие листы
- Взаимодействие с Java