:D 和 :D: 有什么区别?
What's the difference between :D and :D:?
我在浏览 Perl 6 docs on the shift
routine 时看到了这个片段:
Defined as:
multi sub shift(Array:D )
multi method shift(Array:D:)
我知道 :D
表示 Array
是 defined
而不是 Any
或 Nil
,但是 :D:
是什么?好难找。
This section 类型签名文档包含更多语法示例,但没有(据我所知)解释它。
方法的调用者作为隐式第一个参数传递。如果你想在签名中使用一个明确的参数(例如添加一个笑脸类型 :D
或者只是给它一个更具描述性的名称),你需要用 :
而不是,
来自参数列表的其余部分。即使在空列表的情况下,这也是必要的,因此可以从具有常规位置参数的签名中消除歧义。
可以找到更多信息 in the design documents。
Christoph 的回答已经很好了。我的回答是试图通过一个具体的小例子来提供一些背景信息。
正如 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 所说,此语法 "is necessary even in case of [a paratemer-less signature] so it can be disambiguated from a signature with a regular positional parameter." 因此:
# 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
),则你可以使用 type
微笑: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 中,方法可以限制为仅在 class 的对象实例(对于 对象方法)或仅在 class本身(对于class方法);您只需要将 :D
笑脸添加到对象方法的 class 名称,将 :U
笑脸添加到 class 方法的 class 名称:
method object-method( CLASSNAME:D : ) { ... }
method class-method( CLASSNAME:U : ) { ... }
但是,这并不像一般情况那样,相反,您可以使用编译时变量 ::?CLASS
来确定当前的 class,从而消除将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 ~ '.'
}
我在浏览 Perl 6 docs on the shift
routine 时看到了这个片段:
Defined as:
multi sub shift(Array:D ) multi method shift(Array:D:)
我知道 :D
表示 Array
是 defined
而不是 Any
或 Nil
,但是 :D:
是什么?好难找。
This section 类型签名文档包含更多语法示例,但没有(据我所知)解释它。
方法的调用者作为隐式第一个参数传递。如果你想在签名中使用一个明确的参数(例如添加一个笑脸类型 :D
或者只是给它一个更具描述性的名称),你需要用 :
而不是,
来自参数列表的其余部分。即使在空列表的情况下,这也是必要的,因此可以从具有常规位置参数的签名中消除歧义。
可以找到更多信息 in the design documents。
Christoph 的回答已经很好了。我的回答是试图通过一个具体的小例子来提供一些背景信息。
正如 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 所说,此语法 "is necessary even in case of [a paratemer-less signature] so it can be disambiguated from a signature with a regular positional parameter." 因此:
# 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
),则你可以使用 type
微笑: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 中,方法可以限制为仅在 class 的对象实例(对于 对象方法)或仅在 class本身(对于class方法);您只需要将 :D
笑脸添加到对象方法的 class 名称,将 :U
笑脸添加到 class 方法的 class 名称:
method object-method( CLASSNAME:D : ) { ... }
method class-method( CLASSNAME:U : ) { ... }
但是,这并不像一般情况那样,相反,您可以使用编译时变量 ::?CLASS
来确定当前的 class,从而消除将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 ~ '.'
}