有什么区别:D和:D:?

cat*_*cat 15 perl6 raku

我正在浏览例程中Perl 6文档shift并看到了这个片段:

定义为:

multi sub    shift(Array:D )
multi method shift(Array:D:)
Run Code Online (Sandbox Code Playgroud)

我知道:D指的Array就是definedAnyNil,但有什么:D:?搜索起来非常困难.

类型签名文档的这一部分包含更多语法示例,但没有(据我所知)解释它.

Chr*_*oph 13

方法的调用作为隐式的第一个参数传递.如果要在签名中使用显式参数(例如,为了添加类型笑脸:D或仅为其提供更具描述性的名称),则需要将其与a :而不是,参数列表的其余部分分开.即使在空列表的情况下,这也是必要的,因此可以从具有常规位置参数的签名中消除歧义.

可以在设计文档中找到更多信息.


uzl*_*xxx 6

克里斯托夫的回答已经很出色了。我的回答是尝试通过一个具体的小例子来提供一些背景信息。

\n

正如 Christoph 所说,在 Raku 中,方法的调用者作为隐式的第一个位置参数传递,然后该参数可用于方法的主体,如下所示self

\n
class Person {\n    has $.name;\n    \n    method greet( Person $B, $greeting = \'Hello\' ) {\n        self.name ~ ": $greeting, " ~ $B.name ~ \'.\'\n    }\n}\n\nmy $john = Person.new(name => \'John\');\nmy $dana = Person.new(name => \'Dana\');\nsay $john.greet($dana, \'Good morning\'); # \xc2\xabJohn: Good morning, Dana.\xc2\xbb\n
Run Code Online (Sandbox Code Playgroud)\n

如果您希望将其绑定到其他内容,请使用您在方法中声明的常规参数(位置参数和命名参数)的method meth-name( invocant : param1, param2, ..., param3) { ... } 语法。param1, param2, ..., param3正如 Christoph 所说,这种语法“即使在[无参数签名]的情况下也是必要的,因此它可以与具有常规位置参数的签名消除歧义。” 所以:

\n
# Person A greets person B.\nmethod greet( $A : Person $B, $greeting = \'Hello\' ) {\n    $A.name ~ ": $greeting, " ~ $B.name ~ \'.\'\n}\n
Run Code Online (Sandbox Code Playgroud)\n

您可以更进一步,输入调用者,不一定是因为需要它,而是因为它使方法的签名更具描述性:

\n
# Person A greets person B.\nmethod greet( Person $A : Person $B, $greeting = \'Hello\' ) {\n    $A.name ~ ": $greeting, " ~ $B.name ~ \'.\'\n}\n
Run Code Online (Sandbox Code Playgroud)\n

如果您不希望该方法greet接受类型对象(例如,Person),而只接受该类型的对象实例(例如,Person.new),那么您可以使用类型\nsmily :D。因此:

\n
# Person A greets person B.\nmethod greet( Person:D $A : Person $B, $greeting = \'Hello\' ) {\n    $A.name ~ ": $greeting, " ~ $B.name ~ \'.\'\n}\n
Run Code Online (Sandbox Code Playgroud)\n

类型表情符号:D(对于DEFINED )、:U(对于未定义) 和(这是不使用或 的:_类型的隐式表情符号)。:D:U

\n

self如果您从方法的签名中删除显式调用者(并恢复为 using ),那么您最终会得到与问题中类似的内容。在这里我只是使用一些空白来让它看起来不那么令人畏惧:

\n
method greet( Person:D : Person $B, $greeting = \'Hello\' ) {\n    self.name ~ ": $greeting, " ~ $B.name ~ \'.\'\n}\n
Run Code Online (Sandbox Code Playgroud)\n
\n

附录:

\n

在 Raku 中,方法可以限制为仅在类的对象实例上调用(对于对象方法)或仅在类本身上调用(对于类方法);您只需将:D笑脸添加到对象方法的类名称中,并将:U笑脸添加到类方法的类名称中:

\n
method object-method( CLASSNAME:D : ) { ... }\nmethod class-method( CLASSNAME:U : ) { ... }\n
Run Code Online (Sandbox Code Playgroud)\n

但是,这并不像可能的那样通用,您可以使用编译时变量::?CLASS来确定当前类,从而无需将类名称放在那里。例如,限制greet仅在以下实例对象上调用Person

\n
method greet( ::?CLASS:D: Person $B, $greeting = \'Hello\' ) {\n    self.name ~ ": $greeting, " ~ $B.name ~ \'.\'\n}\n
Run Code Online (Sandbox Code Playgroud)\n

与往常一样,如果您对冒号感到困惑,您总是可以在类型 smily 所附加的任何内容和其余内容之间放置一些空格,:以使内容更加明显,如下所示:

\n
method greet( ::?CLASS:D : Person $B, $greeting = \'Hello\' ) {\n    self.name ~ ": $greeting, " ~ $B.name ~ \'.\'\n}\n
Run Code Online (Sandbox Code Playgroud)\n