如何在Perl 6中为现有类添加方法?

bri*_*foy 14 perl6 raku

int类有一个方法is_prime,所以我想,只是笑声,我想一些其他方法增加Int了一些做数论的东西我的爱好项目.

我以为我可以这样做:

class Int {
    method is-even (Int:D $number ) returns Bool:D {
        return False if $number % 2;
        return True;
        }
    }

say 137.is-even;
Run Code Online (Sandbox Code Playgroud)

但这不起作用:

===SORRY!===
P6opaque: must compose before allocating
Run Code Online (Sandbox Code Playgroud)

我不知道这是否意味着我不能这样做或者我做错了.

我可以很容易地创建一个继承自的新类Int,但这不是我感兴趣的:

class MyInt is Int {
    method is-even () returns Bool:D {
        return False if self % 2;
        return True;
        }
    }

my $n = MyInt.new(138);
say $n.is-even;
Run Code Online (Sandbox Code Playgroud)

我不是在寻找变通方法或替代解决方案.

Chr*_*oph 15

这有语法糖 - augment:

use MONKEY-TYPING;

augment class Int {
    method is-even() returns Bool:D {
        return False if self % 2;
        return True;
    }
}
Run Code Online (Sandbox Code Playgroud)

增加一个课程被认为是危险的有两个原因:第一,远距离行动,第二,因为(据我所知),有潜力 未定义的行为 deoptimization,因为它可能会使各种方法缓存处于无效状态.

因此,MONKEY-TYPING在允许使用之前提供pragma 的要求.

另外,请注意is-even可以写得更紧凑self %% 2.


bri*_*foy 5

呵呵,这有效,我以为我以前尝试过,而且比我在问题中提出的要好。

Int.^add_method( 'is-even', method () returns Bool:D {
    return False if self % 2;
    return True;
    } );

say 137.is-even;
Run Code Online (Sandbox Code Playgroud)

不过,我不确定这是否行得通。该add_method文档说的类型由之前,我们只能这样做。如果我打电话Int.^methodsis-even显示不出来。尽管如此,它似乎是可以调用的并且做对了。

词汇方法

玩多了,我想我可以创建一个不附加到任何类的方法,然后在一个对象上调用它:

my &is-even = method (Int:D :) returns Bool:D { self %% 2 };
Run Code Online (Sandbox Code Playgroud)

这构造了一个Callable(请参阅&is-even.WHAT)。在签名中,我将其约束为一个确定的Int值(Int:D),但未为其命名。我在类型约束之后添加冒号,以注意第一个参数是倡导者。现在,我可以将该方法应用于我喜欢的任何对象:

say 137.&is-even;
say 138.&is-even;
say "foo".&is-even;  # works, although inside is-even blow up
Run Code Online (Sandbox Code Playgroud)

因为它是词法,所以在不同的维度上很好,但是在错误类型的对象可能会调用它的情况下不好。在认为它具有可以分派到的方法后,该错误就会出现。

  • 我不认为它被记录在案,我什至不能 100% 确定我的建议是合理的 - 只是 `Perl6::Metamodel::MethodContainer.add_method` 使用参数 0 执行 `nqp::setmethcacheauth`,而 ` Perl6::Metamodel::ClassHOW.compose` 调用`Perl6::Metamodel::MROBasedMethodDispatch.publish_method_cache` 再次设置`nqp::setmethcacheauth` (2认同)