Почему `eq` не работает, если один аргумент перегружен строкой?

Я понял (трудный путь), что оператор eq выдает фатальную ошибку времени выполнения, когда один из операндов является объектом с перегруженной строковой спецификацией.

Вот минимальный пример:

my $test = MyTest->new('test');
print 'yes' if $test eq 'test';

package MyTest;

use overload '""' => sub { my $self = shift; return $self->{'str'} };

sub new {
    my ( $class, $str ) = @_;
    return bless { str => $str }, $class;
}

Результат выполнения этого:

Operation "eq": no method found,
    left argument in overloaded package MyTest,
    right argument has no overloaded magic at ./test.pl line 7.

Я ожидаю, что чтение perlop будет заключаться в том, что строковый контекст будет принудительно установлен на обоих операндах, запуская метод строкового $test, затем полученные строки сравниваются. Почему это не работает? Что на самом деле происходит?

Контекст, в котором у меня была эта проблема, был в сценарии, который использует оба autodie а также Try::Tiny, в try блок, я die с некоторыми конкретными сообщениями, которые будут пойманы. Но в catch блок, когда я проверяю $_ eq "my specific message\n" это дает время выполнения, если $_ является autodie::exception,

Я знаю, мне придется заменить $_ eq "..." с !ref && $_ eq "...", но я хотел бы знать, почему.

1 ответ

Решение

Вы только перегружены строковой спецификацией, а не сравнением строк. overload Прагма, однако, будет использовать перегруженную строку для сравнения строк, если вы укажете fallback => 1 параметр:

my $test = MyTest->new('test');
print 'yes' if $test eq 'test';

package MyTest;

use overload
    fallback => 1,
    '""' => sub { my $self = shift; return $self->{'str'} };

sub new {
    my ( $class, $str ) = @_;
    return bless { str => $str }, $class;
}

Подробности о том, почему это работает:

Когда передается перегруженный объект, eq Оператор попытается вызвать eq перегрузки. Мы не обеспечили перегрузку, и мы не предоставили cmp перегрузка от которой eq может быть сгенерирован автоматически. Поэтому Perl выдаст эту ошибку.

С fallback => 1 Если эта опция включена, ошибка подавляется, и Perl в любом случае будет делать то, что он будет делать, - приводить аргументы к строкам (что вызывает перегрузку строкового преобразования или другую магию) и сравнивать их.

Другие вопросы по тегам