Знаки Раку обозначают характер базовой переменной (например, $scalar, @positional, %associative, &code).
Можно объявить переменную без сигила с помощью обратной косой черты (например, \some-variable), а затем обратиться к ней без сигила (например, some-variable).
Просто интересно, в каких случаях предпочтительнее использовать переменную без сигилов?
Объявления формы my \a = expr
вводят псевдоним a
для выражения expr
, не навязывая ему какой-либо контекст, как это сделало бы присваивание сигилированной переменной. Таким образом, их основное использование - это когда вы не хотите иметь какую-либо семантику, связанную с какой-либо сигилой.
Лично я чаще всего использую их, когда создаю конвейеры ленивой обработки и хочу назвать части. В качестве простого примера:
my $fh = open 'somefile';
my \no-comments = $fh.lines.grep({ not /^\s*'#'/ });
for no-comments -> $sig-line {
...
}
grep
возвращает Seq
, который при повторении выполнит операцию. Если бы вместо этого я использовал переменную @
-sigil:
my $fh = open 'somefile';
my @no-comments = $fh.lines.grep({ not /^\s*'#'/ });
for @no-comments -> $sig-line {
...
}
Тогда, несмотря на то, что результаты будут такими же, производительность памяти будет совсем другой: присваивание нетерпеливо, если оно не встречает что-то явно помеченное как ленивый, и поэтому все строки без комментариев будут сохранены в @no-comments
, а затем итерированы по ним. Таким образом, все эти строки остаются в памяти, тогда как в версии без подписи обработанные строки, если они не хранятся где-либо еще, могут быть удалены сборщиком мусора.
Я мог бы использовать сигил $
, но это подразумевает один элемент, а это означает, что если я сделаю это:
my $fh = open 'somefile';
my $no-comments = $fh.lines.grep({ not /^\s*'#'/ });
for $no-comments -> $sig-line {
...
}
Это не сработает (будет выполнена одна итерация цикла, связывающая Seq
в $sig-line
); Я должен был бы каким-то образом преодолеть характер предмета:
my $fh = open 'somefile';
my $no-comments = $fh.lines.grep({ not /^\s*'#'/ });
for $no-comments<> -> $sig-line {
...
}
Связанное использование - при написании универсального кода, который не хочет применять какой-либо контекст:
sub log-and-call(&foo, \value) {
note(value.raku);
foo(value)
}
Опять же, если бы мы использовали $
, мы могли бы добавить оболочку элемента и потенциально повлиять на поведение foo
.
Другие варианты использования, которые я видел:
Есть места, где компилятор использует сигил для оптимизации, например, присваивание анализируется, компиляция привязки параметров использует его, и я думаю, что есть оптимизации на основе сигилов вокруг интерполяции в регулярных выражениях. Однако, поскольку Scalar
является контейнером и, следовательно, объектом, использование сигильной переменной $
вместе с присваиванием подразумевает дополнительное выделение. Однако Scalar
контейнеры также часто можно устранить с помощью JIT-анализа и оптимизации скалярной замены. В общем, не все так очевидно!
Поскольку они являются константами, мне нравится использовать их при копировании алгоритмов и формул из учебников.
Это облегчает проверку на наличие ошибок.
Боже, кажется, это действительно единственное место, где можно задать такой очевидный вопрос: если вы объявляете переменную, такую как
my \sigil-less;
, есть ли какие-либо неотъемлемые преимущества / преимущества производительности, если позже в вашем коде вы принуждаете к $scalar или @positional или %associative или &code ?? На мой взгляд, приведение через конструкции$(sigil-less)
,@(sigil-less)
,%(sigil-less)
и&(sigil-less)
выглядит совершенно естественным и интуитивно понятным, хотя компиляторRakudo
может жаловаться на обратное.