Написание однострочных программ только в 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!