На сегодня осталось рассмотреть возможности для управления поведением именованных аргументов. Возможностей немного, но они есть.
Именованные параметры
Перед тем как начать — вопрос: что должна вывести вот такая программа, если ее запустить без каких-либо параметров?
sub MAIN(:$value) { say "value=$value" }
Ответ может показаться неожиданным:
$ perl6 main-6.pl Use of uninitialized value $value of type Any in string context. Methods .^name, .perl, .gist, or .say can be used to stringify it to something meaningful. in sub MAIN at main-6.pl line 1 value=
Вместо примера использования мы получили сообщение об ошибке, которое говорит о том, что функция MAIN была-таки вызвана. То есть именованные аргументы не являются обязательными.
При этом если указать аргумент, отсутствующий в сигнатуре, все работает как надо:
$ perl6 main-6.pl --key=42 Usage: main-6.pl [--value=<Any>]
Решение проблемы может быть очень легким: если вы действительно ожидаете параметр, укажите, что он должен быть определен (defined):
sub MAIN(Str:D :$value) { say "value=$value" }
Теперь появляется желанный пример использования:
$ perl6 main-6.pl Usage: main-6.pl [--value=<Str>]
Именованные и позиционные параметры
Для параметров, в том числе и для именованных, возможно указать значение по умолчанию. Например:
sub MAIN($value, :$key = 'default') { say "$key=$value" }
В этом случае программа, запущенная без именованного параметра, тоже покажет пример использования, а не ошибку:
$ perl6 main-7.pl Usage: main-7.pl [--key=<Any>] <value>
ОК, но теперь возникает другая проблема. Последняя программа ожидает, что именованный параметр передан до позиционного.
Так работает:
$ perl6 main-7.pl --key=answer 42 answer=42
А так нет:
$ perl6 main-7.pl 42 --key=answer Usage: main-7.pl [--key=<Any>] <value>
Чтобы заработало и во втором примере, нужно сообщить об этом через специальную динамическую переменную:
my %*SUB-MAIN-OPTS = :named-anywhere; sub MAIN($value, :$key = 'default') { say "$key=$value" }
Довольно многословно, но как есть. Теперь можно передавать именованные параметры в любом месте командной строки.
Обязательное =
Наконец, следует обратить внимание на то, что значения именованных параметров требуют знака равенства и отсутствие пробелов вокруг него. Запись в командной строке --key answer 42 будет расценена как три аргумента.
А если значение не указано, то оно будет истиной:
$ perl6 main-7.pl --key 42 True=42
Итого, нельзя сказать, что все мегаудобно, но во многих случаях разбор параметров командной строки получается довольно простым.
В случае использования обязательного и необязательного именованных параметров есть какое-то готовое решение?
——
multi sub MAIN(
Str:D :$key,
Int :$int_key
) {
say «key = $key»;
say «int_key = $int_key»;
}
——
Работает ожидаемо:
c:\>perl6 perl6_test.pl.txt
Usage:
perl6_test.pl.txt [—key=] [—int_key=]
c:\>perl6 perl6_test.pl.txt —key=’aaa’ —int_key=’42’
Usage:
perl6_test.pl.txt [—key=] [—int_key=]
c:\>perl6 perl6_test.pl.txt —key=’aaa’ —int_key=42
key = ‘aaa’
int_key = 42
Но:
c:\>perl6 perl6_test.pl.txt —key=’aaa’
key = ‘aaa’
Use of uninitialized value of type Int in string context.
Methods .^name, .perl, .gist, or .say can be used to stringify it to something m
eaningful.
in sub MAIN at perl6_test.pl.txt line 18
int_key =
Т.е. в последнем случае хотелось бы избежать применения if $int_key {say «int_key = $int_key»;}, если это возможно «штатным» образом работы с MAIN.
Не на сто процентов то самое:
c:\>perl6 perl6_test.pl.txt —key=’aaa’
key = ‘aaa’
int_key = 0
Но покороче, чем через if. Да и на практике вряд ли исключительно вывод этого параметра будет нужен, так что годится, спасибо.