메인 메서드

메인 메서드 (Main Methods)

Scala 3는 명령줄에서 실행할 수 있는 프로그램을 정의하는 새 방법을 제공해요. 메서드에 @main 애너테이션을 붙이면 그 메서드가 실행 가능한 프로그램이 되는 거죠.

출처: Scala 3 Reference

본문

예시를 볼게요.

@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을 가진다. mainArray[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 메서드를 쓰는 걸 권장해요.

더 알아보기 (Learn more)