克里斯托夫的回答已经很好了。我的回答是试图通过一个小的具体例子来提供一些背景信息。
正如 Christoph 所说,在 Raku 中,方法的调用者作为隐式的第一个位置参数传递,然后作为 self 提供给方法的主体:
class Person {
has $.name;
method greet( Person $B, $greeting = 'Hello' ) {
$A.name ~ ": $greeting, " ~ $B.name ~ '.'
}
}
my $john = Person.new(name => 'John');
my $dana = Person.new(name => 'Dana');
say $john.greet($dana, 'Good morning'); # «John: Good morning, Dana.»
如果您希望将其绑定到其他对象,请使用语法method meth-name( invocant : param1, param2, ..., param3) { ... },其中param1, param2, ..., param3 是您在方法中声明的常规参数(包括位置参数和命名参数)。正如 Christoph 所说,这种语法“即使在 [无参数签名] 的情况下也是必要的,因此可以将其与具有常规位置参数的签名消除歧义。”因此:
# Person A greets person B.
method greet( $A : Person $B, $greeting = 'Hello' ) {
self.name ~ ": $greeting, " ~ $B.name ~ '.'
}
您可以更进一步,输入调用者,不一定是因为它是必需的,而是因为它使方法的签名更具描述性:
# Person A greets person B.
method greet( Person $A : Person $B, $greeting = 'Hello' ) {
$A.name ~ ": $greeting, " ~ $B.name ~ '.'
}
如果您不希望方法 greet 接受类型对象(例如,Person),而是只接受该类型的对象实例(例如,Person.new),那么您可以使用 类型
笑脸 :D。因此:
# Person A greets person B.
method greet( Person:D $A : Person $B, $greeting = 'Hello' ) {
$A.name ~ ": $greeting, " ~ $B.name ~ '.'
}
type smilies 是:D(用于D定义)、:U(用于Undefined)和:_(这是隐含的笑脸对于既不使用 :D 也不使用 :U 的类型)。
如果您从方法的签名中删除显式调用者(并恢复使用self),那么您最终会得到与您的问题类似的内容。在这里,我只是使用一些空格来让它看起来不那么令人生畏:
method greet( Person:D : Person $B, $greeting = 'Hello' ) {
self.name ~ ": $greeting, " ~ $B.name ~ '.'
}
附录:
在 Raku 中,方法可以被限制为仅在类的对象实例上调用(对于对象方法)或仅在类本身上调用(对于类方法) ;您只需将:D smily 添加到对象方法的类名中,并将:U smily 添加到类方法的类名中:
method object-method( CLASSNAME:D : ) { ... }
method class-method( CLASSNAME:U : ) { ... }
但是,这并不通用,相反,您可以使用编译时变量::?CLASS 确定当前类,从而无需将类的名称放在那里。例如,将greet 限制为仅在Person 的实例对象上调用:
method greet( ::?CLASS:D: Person $B, $greeting = 'Hello' ) {
self.name ~ ": $greeting, " ~ $B.name ~ '.'
}
和往常一样,如果您对冒号感到困惑,您总是可以在附加类型 smily 的任何东西和剩余的 : 之间放置一些空格,以使事情更明显,例如:
method greet( ::?CLASS:D : Person $B, $greeting = 'Hello' ) {
self.name ~ ": $greeting, " ~ $B.name ~ '.'
}