使用 "make" 时 Raku 语法操作抛出 "Cannot bind attributes in a Nil type object. Did you forget a '.new'?" 错误

Raku grammar action throwing "Cannot bind attributes in a Nil type object. Did you forget a '.new'?" error when using "make"

我在 class 中有这个方法,它会抛出 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);
}

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

错误 - 这里有点猜测,但看起来这个错误是在创建新对象期间生成的。那指向行 my $tc = Lingua::EN::Titlecase.new($match)。我想知道你是否想将 Str 传递到这个函数调用中,例如"$match"~$match...

method content($match) {

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

$match.make($new_title);

提到Nil是因为action方法中较早的匹配失败导致$/被设置为Nil

我猜你避免了更惯用的 $/ 作为 action 方法的参数,因为它妨碍了在 action 方法中进行进一步匹配。在动作方法中做进一步匹配意味着文本被解析两次(一次在语法中,一次在动作中),效率不高,通常最好避免(通过将解析工作移动到语法中)。

作为最后的风格要点,在 method 中声明语法和动作 类 如果它们仅在那里使用,则它们是简洁的封装,但明智的做法是 my 限定它们的范围(my grammar FindHeaders { ... }),否则它们最终将安装在最近的封闭包中。