Почему `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
, затем сравниваются полученные строки, Почему это не работает? Что на самом деле происходит?
Контекст, в котором я столкнулся с этой проблемой, был в script, который использует как 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 будет делать то, что он будет делать в любом случае, - принуждение аргументов к строкам (которое вызывает перегрузку строения или другую магию) и сравнить их.