【问题标题】:What's the difference between :D and :D:?:D 和 :D: 有什么区别?
【发布时间】:2016-02-15 21:31:37
【问题描述】:

我在浏览Perl 6 docs on the shift routine 时看到了这个sn-p:

定义为:

multi sub    shift(Array:D )
multi method shift(Array:D:)

我知道:D 表示Array 是defined 而不是Any 或Nil,但:D: 是什么?很难搜索。

类型签名文档的This section 包含更多语法示例,但没有(据我所知)解释它。

【问题讨论】:

    标签: raku


    【解决方案1】:

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

    更多信息可以在in the design documents找到。

    【讨论】:

      【解决方案2】:

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

      正如 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 ~ '.'
      }
      

      【讨论】:

      • 很好的答案,第二个代码块说 self.name 但可能应该说 $A.name 因为 self 未绑定
      • 我会指出::?CLASS 在那里,这样您就不必将类的名称放在那里。 (这也有效。)
      • @cat 感谢您指出这一点;我已经纠正了。 @BradGilbert 我已经指出了为什么 ::?CLASS 在那里。顺便说一句,如果您认为可以进一步改进,请随时编辑答案;-)。谢谢。
      猜你喜欢
      • 1970-01-01
      • 2014-05-30
      • 1970-01-01
      • 1970-01-01
      • 2015-08-17
      • 1970-01-01
      • 1970-01-01
      • 2010-10-11
      • 2017-04-07
      相关资源
      最近更新 更多