perl6 rakudo 2016.11 match пытается присвоить переменную только для чтения, почему не в 2016.07?
У меня есть следующий метод в классе действий, который хорошо работал в Rakudo 2016.07, но я только что установил 2016.11, и теперь новый Rakudo говорит, что мой метод пытается присвоить переменную только для чтения, и я просто не вижу проблемы:
method ptName ($/) {
my $nameStr = $/.Str, my $lastName, my $firstName;
my $newMatch # this is line 182;
# Cannot assign to a readonly variable or a value
= $nameStr.match(/ \" (<alpha>+) .*? \, \s* (<alpha>+) .*? \" /);
$lastName = $newMatch[0];
$firstName = $newMatch[1];
make "$lastName $firstName";
}
Все сообщение об ошибке
Cannot assign to a readonly variable or a value
in method ptName at /home/lisprog/Binary/grammar.pl line 182
in regex ptName at /home/lisprog/Binary/grammar.pl line 151
in regex TOP at /home/lisprog/Binary/grammar.pl line 137
in block <unit> at /home/lisprog/Binary/grammar.pl line 217
Какие спецификации языка изменились? Пожалуйста помоги. Благодарю.
================================================== ===
Спасибо, Райф, Кристоф, ZZ!! Я не знаю, как добавить длинный комментарий с правильным форматированием. Итак, я добавляю комментарии к своему посту.
Я написал тестовую программу, и теперь кажется, что если я не использую ($/) в сигнатуре метода, потому что я должен использовать.match внутри метода, я больше не могу ничего делать. Что я сделал не так? Вот программа испытаний и результаты:
Тестовая программа:
grammar test {
regex TOP { <foo><bar> }
regex foo { :i \s* foo \s* }
regex bar { :i \s bar \s* }
}
class actTest {
method foo ($x) { # program fails if I use $/ in signature
print "1 "; say $x; # how to combine the 2 and show $x as match?
print "2 "; say $x.WHAT;
my $newStr = $x.Str;
print "3 "; say $newStr;
my $newMatch
= $newStr.match(/:i(f)(oo)/); # adverb cannot be outside?
print "4 "; say $newMatch.WHAT;
print "5 "; say $newMatch;
print "6 "; say $/;
my $oo = $newMatch[1].Str;
print "10 "; say $oo;
my $f = $newMatch[0].Str;
print "11 "; say $f;
my $result = $oo ~ $f;
print "12 "; say $result;
make $result; # now I cannot make anything; huh???
}
method TOP ($/) {
print "8 "; say $<bar>;
print "9 "; say $<foo>.made; # failed, method 'foo' makes nothing
make $<bar> ~ $<foo>.made;
}
}
my $m = test.parse("Foo bar", actions => actTest.new);
print "7 "; say $m;
И результаты:
1 「Foo 」
2 (Match)
3 Foo
4 (Match)
5 「Foo」
0 => 「F」
1 => 「oo」
6 「Foo」
0 => 「F」
1 => 「oo」
10 oo
11 F
12 ooF
1 「Foo」
2 (Match)
3 Foo
4 (Match)
5 「Foo」
0 => 「F」
1 => 「oo」
6 「Foo」
0 => 「F」
1 => 「oo」
10 oo
11 F
12 ooF
8 「 bar」
9 (Any)
Use of uninitialized value of type Any in string context.
Methods .^name, .perl, .gist, or .say can be used to stringify it to
something meaningful.
in method TOP at matchTest.pl line 28
7 「Foo bar」
foo => 「Foo」
bar => 「 bar」
3 ответа
Здесь есть два вопроса, и я отвечу на каждый по очереди:
1) match tries to assign to read-only variable
Он пытается установить $/, который у вас уже есть в вашей области видимости и только для чтения. Вы можете просто использовать другое имя в подписи для грамматики $/. Я вижу, что вы сразу принуждаете его к Str, так почему бы не позволить подписи сделать это:
method ptName (Str() $nameStr) { ... }
2) why not in 2016.07?
Новое поведение не является ошибкой, и основная команда решила, что текущее поведение желательно (РЕДАКТИРОВАТЬ: фактически, при дальнейшем рассмотрении кажется, что старое поведение было ошибкой, когда.match молча не смог установить $/, если он был только для чтения),
Итак, главный вопрос: почему вообще изменилось поведение?
Хотя существует очевидная цель, чтобы поведение оставалось неизменным, чтобы пользователи могли на него полагаться, нам также необходимо улучшить работу и двигаться вперед. Как это работает, у нас есть огромный набор тестов, который мы называем Roast. Если в код внесено изменение, которое нарушает тест, это изменение нельзя сделать на текущем языке, и его следует отложить до следующего языкового выпуска (с тех пор пользователи могут использовать use v6.c
или что-то еще, чтобы старое поведение).
Однако, если набор тестов пройден, это означает, что все изменения не были завершены, и мы можем изменить их, не дожидаясь следующего языкового выпуска. Это случай здесь, с .match
,
Очевидно, что мы не хотим, чтобы наши пользователи проходили через наш набор тестов в поисках того, что тестируется, а что нет, поэтому наша документация следует политике, согласно которой мы не документируем вещи, которые не покрыты жарким.
Это в настоящее время имеет место с .match
метод, который вы использовали. Я не уверен, где вы узнали об этом, так как в конце сентября я создал документ, в котором указывается .match
не было документировано, так что тогда его не было в документации, и он ожидал, что поработает lizmat, который изменил поведение, которое вас укусило.
Поэтому я надеюсь, что это отвечает на некоторые вопросы. Я понимаю, что такое нарушение кода довольно прискорбно, и мы бы хотели, чтобы это происходило как можно реже, но в то же время нам нужно улучшить язык. Надеемся, что по мере развития реализации будет все меньше и меньше таких непроверенных и недокументированных возможностей.
Ура, ZZ
В соответствии с git blame src/core/Str.pm
Лизмат работал на это в октябре. Str.match
теперь будет возиться с лексическим $/
вызывающего блока, когда он, очевидно, не делал этого раньше.
Это означает Str.match
вернет свой результат дважды: сначала как его возвращаемое значение, а второй раз вне диапазона, установив $/
, В то время как регулярное выражение приложения через ~~
делает это также (что необходимо, чтобы вы могли использовать синтаксический сахар, как $0
или же $<foo>
) Я не уверен Str.match
должен. Если раньше он этого не делал, я подозреваю, что это может быть ошибкой: либо сообщите об этом, либо спросите в #perl6
на Freenode об этом.
Как указывает Zoffix, это было старое поведение, $/
всегда должен был быть установлен, но неспособность сделать это просто не вызывала исключения.
Я хочу поблагодарить ZZ, Christoph, raiph и smls за то, что они уделили мне драгоценное время. Моя проблема была решена
(1) использование сигнатуры метода, отличного от $/, и (2) использование объекта соответствия сигнатуры для создания вместо использования $ / для создания.
Пожалуйста, также обратитесь к ответам на https://stackru.com/posts/41027321/revisions
Большое спасибо!!
You can also use an immediately-invoked lambda: -> $x { my $/; $x.match(/regex/) }($/)