Wait the light to fall

在 Raku 中怎么为已存在的类添加方法

焉知非鱼

Add a Method to an Existing Class in Raku

Raku 中怎么为已存在的类添加方法 #

Int 类有一个方法叫做 is-prime, 我想为 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;

通过类的继承也是一种方法, 但是不是我想要的。Swift 中可以通过扩展来实现, Raku 中有一个 add_method 方法:

method add_method(Metamodel::MethodContainer: $obj, $name, $code)

这会给元类(meta class)添加一个方法, 使用 $name 作为调用的方法名。这只会在类型被组合前使用。

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

say 137.is-even;
say Int.^methods;

如果我调用 Int.^methods 时, is-even 没有出现。但是上面的代码能被调用并起作用了。

Int.^add_method('fac', method () returns Int:D {
     return 1 if self == 0;
     return 1 if self == 1;
     my $sum = 1; for 1 .. self  {$sum *= $_}; return $sum;
});

1.fac # 1
5.fac # 120

method 后面的圆括号是方法的签名:

Int.^add_method('power', method (Int $num) returns Int:D {
     return self ** $num;
});

2.power(3).say;  # 8
2.power(10).say; # 1024

词法方法 #

我可以让方法不依附于任何类, 并且能在对象上调用该方法:

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