主要方法
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
方法。