在 GitHub 上编辑此页面

主要方法

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 注解的方法可以编写在顶层或静态可访问的对象中。程序的名称在每种情况下都是方法的名称,不包含任何对象前缀。 @main 方法可以具有任意数量的参数。对于每个参数类型,必须存在一个 scala.util.CommandLineParser.FromString[T] 类型类实例,用于将参数字符串转换为所需的参数类型 T。主方法的参数列表可以以一个重复参数结尾,该参数将接收命令行上给出的所有剩余参数。

@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 的静态方法,具有通常的签名。它接受一个 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 用户程序中不可用。常规的“静态”成员在 Scala 中使用对象生成。

@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 方法。