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

时间:2015-12-29 05:18:12

标签: perl6 raku

Int class有一个方法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;

但这不起作用:

===SORRY!===
P6opaque: must compose before allocating

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

我可以很容易地创建一个继承自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;

我不是在寻找解决方法或替代解决方案。

4 个答案:

答案 0 :(得分:15)

这有一个语法糖 - augment

use MONKEY-TYPING;

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

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

因此,在允许使用之前提供MONKEY-TYPING编译指示的要求。

另外,请注意is-even可以更紧凑地编写为self %% 2

答案 1 :(得分:5)

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

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

say 137.is-even;
但是,我不确定这应该有用。 add_method docs表示我们只应在组成类型之前执行此操作。如果我致电Int.^methods,则is-even不会显示。尽管如此,它似乎是可以调用并做正确的事情。

词汇方法

玩更多,我想我可以创建一个没有附加到任何类的方法并在一个对象上调用它:

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

这构造了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

这在一个不同的维度很好,因为它是词法,但不是很好,因为错误类型的对象可能会调用它。在它认为有调度方法后,错误显示出来。

答案 2 :(得分:3)

您还可以通过包含& sygil:

简单地调用子方法
sub is-even(Int $n) { $n %% 2 }
say 4.&is-even;  # True

当然,它只是语法糖,但是当它看起来比简单地调用sub更具可读性时,我已经完成了几次。

(我知道你“不是在寻找解决方法或替代解决方案”,但你自己发布了一些,所以我想,为什么不呢?)

答案 3 :(得分:1)

如果只需要某个类的某些实例,还有另一种有趣的方法可以做到这一点。您可以使用角色来装饰对象:

 my $decorated = $object but role { ... }