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