В чем разница между: D и: D :?

Я просматривал документы Perl 6 о shift подпрограмме и увидел этот фрагмент:

Определяется как:

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

Я знаю :D означает, что Array это defined, а не Any или Nil, но что :D:? Искать очень сложно.

Этот раздел документации по сигнатуре типов содержит больше примеров синтаксиса, но не содержит (насколько я могу судить ) объясни это.


person cat    schedule 15.02.2016    source источник


Ответы (2)


Ответ Кристофа уже отличный. Мой ответ - это попытка дать некоторый контекст на небольшом конкретном примере.

Как утверждает Кристоф, в 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 - обычные параметры (как позиционные, так и именованные), которые вы объявляете в методе. Как утверждает Кристоф, этот синтаксис «необходим даже в случае [подписи без параметров], чтобы можно было устранить неоднозначность подписи с помощью обычного позиционного параметра». Следовательно:

# 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 smily :D. Таким образом:

# Person A greets person B.
method greet( Person:D $A : Person $B, $greeting = 'Hello' ) {
    $A.name ~ ": $greeting, " ~ $B.name ~ '.'
}

Смайлы типа :D (определены для D), :U (для U ndefined) и :_ (это неявный смайлик для типа, который не использует ни :D, ни :U).

Если вы удалите явный активатор (и вернетесь к использованию self) из сигнатуры метода, вы получите что-то похожее на то, что у вас есть в вашем вопросе. Здесь я просто использую пробелы, чтобы это выглядело менее устрашающе:

method greet( Person:D : Person $B, $greeting = 'Hello' ) {
    self.name ~ ": $greeting, " ~ $B.name ~ '.'
}

Приложение:

В Raku методы могут быть ограничены вызовом только для экземпляров объекта класса (для методов объекта) или только для самого класса (для методов класса); вам просто нужно добавить :D смайлик к имени класса для методов объекта и :U смайлик к имени класса для методов класса:

method object-method( CLASSNAME:D : ) { ... }
method class-method( CLASSNAME:U : ) { ... }

Однако это не так широко, как могло бы быть, вместо этого вы можете использовать переменную времени компиляции _ 22_, который определяет текущий класс и, таким образом, избавляет от необходимости указывать имя класса. Например, чтобы ограничить 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 ~ '.'
}
person Luis F. Uceta    schedule 26.01.2020
comment
Отличный ответ, второй блок кода говорит self.name, но, вероятно, должен сказать $A.name, поскольку self не привязан - person cat; 27.01.2020
comment
Я хотел бы указать, что ::?CLASS существует, поэтому вам не нужно указывать там имя класса. (Что тоже работает.) - person Brad Gilbert; 27.01.2020
comment
@cat Спасибо, что указали на это; Я поправил. @BradGilbert Я указал, почему там ::?CLASS. Кстати, не стесняйтесь редактировать ответ, если считаете, что его можно улучшить ;-). Спасибо. - person Luis F. Uceta; 28.01.2020

Вызывающий метода передается как неявный первый аргумент. Если вы хотите использовать явный параметр в сигнатуре (например, чтобы добавить смайлик типа :D или просто дать ему более информативное имя), вам необходимо отделить его с помощью : вместо , от остальной части списка параметров. . Это необходимо даже в случае пустого списка, чтобы можно было устранить неоднозначность подписи с помощью обычного позиционного параметра.

Дополнительную информацию можно найти в проектной документации.

person Christoph    schedule 15.02.2016