Перегрузка операторов для класса - PullRequest
11 голосов
/ 23 апреля 2019

Допустим, у меня есть следующий класс:

class A {
    has $.val;

    method Str { $!val ~ 'µ'  }  
}

# Is this the right way of doing it?
multi infix:<~>(A:D $lhs, A:D $rhs) {
    ('(', $lhs.val, ',', $rhs.val, ')', 'µ').join;
}

Как бы я перегрузил оператор (например, +) для класса таким же образом, как Str в предыдущем классе?

Полагаю, это работает только для методов, которые вызываются для объекта экземпляра, и использование синтаксиса multi operator-type:<OP>(T $lhs, T $rhs) { } для операторов - правильный путь, но я не уверен.

ДляНапример, в Python, кажется, есть соответствие между специальными методами, названными в честь операторов (например, operator.__add__) и операторов (например, +).Кроме того, любая перегрузка оператора для пользовательского класса выполняется внутри класса.

Ответы [ 2 ]

12 голосов
/ 23 апреля 2019

В Perl 6 операторы считаются частью текущего языка .Все вещи, которые относятся к текущему языку, определены лексически (то есть my -области).Следовательно, подпрограмма multi - это правильная вещь.

Если поместить этот код в модуль, вы, вероятно, также захотите пометить multi для оператора с is export:

multi infix:<~>(A:D $lhs, A:D $rhs) is export {
    ('(', $lhs.val, ',', $rhs.val, ')', 'µ').join;
}

Так что он будет доступен пользователям, которые use или import модуль (на самом деле use определен в терминах import, а import импортирует символы в лексическую область).

Хотя есть некоторые операторы, которые по умолчанию делегируют методы (например, prefix:<+> вызывает Numeric), между ними нет отношения 1: 1, и для большинства операторов их реализация напрямуюоператор sub (или распределенный по многим multi sub с).

Кроме того, набор операторов открыт, поэтому нельзя ограничивать перегрузку существующих операторов, но также можно вводить новые.Это поощряется, когда новое значение для оператора явно не связано с нормальной семантикой используемого символа;например, было бы целесообразно перегрузить + для добавления матрицы, но для чего-то, что нельзя было бы рассматривать как дополнение, новый оператор был бы лучшим выбором.

7 голосов
/ 23 апреля 2019
class A {
    has $.val;

    method Str { $!val ~ 'µ'  }
}

multi infix:<~>(A:D $lhs, A:D $rhs) {
    ('(', $lhs.val, ',', $rhs.val, ')', 'µ').join;
}

dd A.new(val => "A") ~ A.new(val  => "B"); # "(A,B)µ"

Так что да, это правильный путь.Если вы хотите переопределить +, тогда имя создаваемого подпрограммы будет infix:<+>.

. Вы также можете указать регистр для объектов типа, используя :U "type smiley", например:

multi infix:<~>(A:U $lhs, A:U $rhs) {
    'µ'
}

Надеюсь, это ответит на ваш вопрос.

...