如何在 MAIN 中要求一个或多个参数

How to require 1 or more of an argument in MAIN

现在,我有一个 MAIN sub 可以接受一个或多个字符串参数。但是我为 MAIN 使用了两个单独的参数来做到这一点:

sub MAIN (
    Str:D $file,
    *@files,
) {
    @files.prepend: $file;

    # Rest of the program
}

现在我想知道是否有更惯用的方法来实现这一点,因为我目前的解决方案感觉有点笨拙,而且不是很 Perly。

也许这里的答案足够好:

sub MAIN(*@a where {.elems > 0 and .all ~~ Str}) {
    say "got at least 1 file name"
}

sub USAGE {
    say "{$*PROGRAM-NAME}: <file-name> [ <file-name> ... ]"
}

基于此处的文档: https://docs.perl6.org/type/Signature#Constraining_Slurpy_Arguments

您也可以尝试使用简单的动态变量:

die "Usage: $*EXECUTABLE <file> <file2>*" if !+@*ARGS;
my @files =  @*ARGS;

其中 @*ARGSan array with the arguments issued into the command line

你甚至可以使用 @*ARGFILES, since they are actually files

你可以用 proto sub

proto sub MAIN ( $, *@ ){*}

multi sub MAIN ( *@files ) {
    # Rest of the program
}

或与sub-signature deparsing

sub MAIN ( *@files ($,*@) ) {
    # Rest of the program
}

冒 "over answering" 的风险 - 我对 "Perly" 的看法尽可能简洁而不晦涩(也许我只是用另外两个主观术语替换了一个... :-)

如果你有一个 "slurpy" 数组作为唯一的参数,那么它会很乐意接受任何超出你在评论中输入的规范的参数。但是,默认情况下位置参数是强制性的,并且 proto's 仅在您想排除对所有 multi 的约束时才是必需的 - 可能对您在这里想要的东西有点矫枉过正。所以,这就足够了:

sub MAIN($file , *@others) {
    say "Received file, $file, and @others.elems() others."
} 

这与 mr_ron 的内容很接近 - 但为什么不使用 MAIN 通过检查您的参数为您提供的默认用法消息:

$ ./f.pl
Usage:
  ./f.pl <file> [<others> ...]

有些人可能会说我通过在第一个参数上删除 Str 类型约束来作弊,但是当您限制为字符串时它确实不会给您带来太多好处,因为数字指定在CLI 以满足 Str 约束的 IntStr 类型(一种混合类型)的形式出现。 OTOH,当将 CLI 参数限制为 Num 或 Int 时,Perl6 将检查您是否实际将数字放在那里 - 或者至少,unicode 认为数字是什么。

如果您想要实际的文件名,您可以通过强制输入 IO() 来节省验证步骤。那么它只会在你命名一个文件时起作用。最后,将 where .r 放在参数之后将坚持它是可读的:

sub MAIN(IO() $file where .r, *@others) { ...

坚持一个强制性参数的短行,该参数是一个引用可读文件的文件名,具有不同数量的其他参数和一条有用的使用消息,如果它全部出现问题,则会自动生成...