Raku 语法操作抛出“无法绑定 Nil 类型对象中的属性。您是否忘记了‘.new’?” 使用“make”时出错

Ste*_*ieD 6 grammar action raku

我在一个抛出异常的类中有这个方法Cannot bind attributes in a Nil type object. Did you forget a '.new'?

method parse() {
    grammar FindHeaders {
        token TOP { [<not-header> | <header>]+ $ }
        token not-header { ^^ <![#]> \N* \n }
        token header { ^^ '#'{ 1 .. 6 } <content> \n }
        token content { \N+ }
    }
    class HeaderActions {
        method content($match) {
            return if $match ~~ m/^^\#\s+<[A..Z]>+e*s/ || $match !~~ m/<[a..z]>/;
            return if $match ~~ m/\|/ && ( $match ~~ m:i/project/ || $match ~~ m:i/\+\w/ );
            my $tc = Lingua::EN::Titlecase.new($match);
            my $new_title = $tc.title;
            make($new_title);
        }
    }

    my $t = $!content;
    FindHeaders.parse($t, actions => HeaderActions.new);
}
Run Code Online (Sandbox Code Playgroud)

据我所知,这段代码与官方文档中的内容相符。所以不确定为什么我会收到此错误。我不知道编译器指的是哪个属性或 Nil 对象。如果我用该方法注释掉该行make,一切都会正常。

Jon*_*ton 8

方法内容($match) {

$/操作方法通常用作参数名称是有原因的:因为make函数会进行查找$/以便将提供的对象与其关联。您可以使用$match,但随后需要调用make该方法:

$match.make($new_title);
Run Code Online (Sandbox Code Playgroud)

提及Nil是因为之前在操作方法中失败的匹配导致$/被设置为Nil

我猜您避免使用更惯用的$/操作方法参数,因为它妨碍了在操作方法中进行进一步匹配。在操作方法中进行进一步匹配意味着文本将被解析两次(一次在语法中,再次在操作中),这不是那么有效,通常最好避免(通过将解析工作移至语法中)。

作为最后一个风格点,method如果语法和操作类仅在此处使用,则在 a 中声明语法和操作类是一种简洁的封装,但明智的做法是对my它们进行范围限制 ( my grammar FindHeaders { ... }),否则它们最终将安装在最近的封闭包中。