6

我在 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」
4

4 回答 4

8

这里有两个问题,我将依次回答:

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您使用的方法目前就是这种情况。我不确定您是从哪里了解到的,因为在 9 月底我创建了一个文档问题,表明.match没有记录,所以当时它不在文档中,正在等待 lizmat 进行的大修,这改变了咬你的行为。

所以我希望这能回答一些问题。我确实理解这样的代码破坏是非常不幸的,我们希望尽可能少地发生这种情况,但同时我们需要改进语言。希望随着实现的成熟,这些未经测试和未记录的功能将越来越少。

干杯,ZZ

于 2016-12-06T15:11:37.037 回答
1

我要感谢 ZZ、Christoph、raiph 和 smls 对我的帮助。我的问题已通过以下方式解决:

  1. 使用 $/ 以外的方法签名,以及
  2. 使用签名匹配对象来制作而不是使用 $/ 来制作。

另请参阅以下答案:perl6 语法操作:如果不使用 $/ 则无法进行任何操作

于 2016-12-08T05:49:08.230 回答
1

git blame src/core/Str.pm, lizmat 于 10 月进行了这项工作。Str.match现在将摆弄$/调用块的词汇,而以前显然没有这样做。

这意味着Str.match将返回它的结果两次:第一次作为它的返回值,第二次通过设置带外$/。虽然正则表达式应用程序 via也这样做(这是必要的,因此您可以使用类似or的~~语法糖),但我不相信应该这样做。$0$<foo>Str.match如果它以前没有这样做,我怀疑它可能是一个错误:要么这样报告它,要么#perl6在 Freenode 上询问它。

正如 Zoffix 指出的那样,旧的行为是错误的,因为$/应该设置,但无法这样做并没有触发异常。

于 2016-12-05T08:56:19.373 回答
0

您还可以使用立即调用的 lambda:-> $x { my $/; $x.match(/regex/) }($/)

于 2020-08-23T15:50:08.413 回答