메인 메서드
메인 메서드 (Main Methods)
Scala 3는 명령줄에서 실행할 수 있는 프로그램을 정의하는 새 방법을 제공해요. 메서드에 @main 애너테이션을 붙이면 그 메서드가 실행 가능한 프로그램이 되는 거죠.
본문
예시를 볼게요.
@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 bldr = new StringBuilder(s"Happy $age$suffix birthday, $name")
for other <- others do bldr.append(" and ").append(other)
bldr.toString
이 코드는 happyBirthday라는 메인 프로그램을 생성하고, 다음과 같이 호출할 수 있어요.
> scala happyBirthday 23 Lisa Peter
Happy 23rd birthday, Lisa and Peter
@main 애너테이션이 붙은 메서드는 최상위(top-level)나 정적으로 접근 가능한 객체 안에 작성할 수 있어요. 프로그램의 이름은 두 경우 모두 메서드의 이름이고, 어떤 객체 접두어도 붙지 않아요. @main 메서드는 매개변수를 원하는 만큼 가질 수 있어요. 각 매개변수 타입에 대해, 인자 문자열을 필요한 타입 T로 변환하는 데 쓰이는 scala.util.CommandLineParser.FromString[T] 타입 클래스의 인스턴스가 반드시 있어야 해요. 메인 메서드의 매개변수 목록은 가변 인자(repeated parameter)로 끝날 수 있는데, 이 가변 인자가 명령줄에 주어진 나머지 모든 인자를 받아요.
@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 컴파일러는 @main 메서드 f로부터 다음과 같이 프로그램을 생성해요.
@main메서드가 발견된 패키지에f라는 이름의 클래스를 만든다.- 그 클래스는 보통의 시그니처를 가진 정적 메서드
main을 가진다.main은Array[String]을 인자로 받고Unit을 반환한다. - 생성된
main메서드는scala.util.CommandLineParser객체의 메서드를 사용해 인자를 변환해서 메서드f를 호출한다.
예를 들어 위의 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에서 보통의 "static" 멤버는 객체(object)를 사용해 생성하거든요.
@main 메서드는 Scala 3에서 명령줄에서 실행할 수 있는 프로그램을 만드는 권장 방식이에요. 이전에는 프로그램을 특별한 부모 클래스 App을 가진 객체로 작성했는데, 그 방식을 대체하죠. Scala 2에서는 happyBirthday를 이렇게도 쓸 수 있었어요.
object happyBirthday extends App:
// needs by-hand parsing of arguments vector
...
이전 App의 기능은 "마법" 트레이트인 DelayedInit에 의존했는데, 그 기능은 더 이상 사용할 수 없어요. App은 한동안 제한된 형태로 존재하긴 하지만, 명령줄 인자를 지원하지 않고 앞으로 폐기될 예정이에요. 프로그램을 Scala 2와 Scala 3 양쪽으로 크로스 빌드해야 한다면, Array[String] 인자를 받는 명시적인 main 메서드를 쓰는 걸 권장해요.