2014-05-01 20 views
14

Zdałem sobie sprawę (na swój sposób), że operator eq daje śmiertelny błąd wykonania, gdy jeden z argumentów jest obiektem z przeciążonym ciągiem.Dlaczego `eq` nie działa, gdy jeden argument ma przeciążone ciągowanie?

Oto minimalne przykład:

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; 
} 

Wynikiem działania jest:

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

Moje oczekiwanie od czytania perlop byłoby, że kontekst ciąg jest zmuszony po obu operandów, wypalanie stringification metoda w $test, a następnie wynikowe ciągi są porównywane. Dlaczego to nie działa? Co tak naprawdę się dzieje?

Kontekst, w którym wystąpił ten problem, dotyczył skryptu, który używa zarówno autodie i Try::Tiny. W bloku try, I die z pewnymi komunikatami, które mają zostać przechwycone. Ale w bloku catch, kiedy testuję pod kątem czy $_ eq "my specific message\n", daje to środowisko wykonawcze, jeśli $_ jest autodie::exception.

Wiem, że będę musiał zastąpić $_ eq "..." z !ref && $_ eq "...", ale chciałbym wiedzieć dlaczego.

+1

spróbuj '" $ test "eq 'test'' –

+0

@HunterMcMillen, który działał, dziękuję. Ale nie widzę różnicy, jaką to czyni dla tłumacza! – scozy

+2

Porównanie 'eq' w rzeczywistości nie zmusza' $ test' do uszeregowania, po prostu użyj porównania łańcuchów na swoich argumentach. –

Odpowiedz

20

Tylko przeciążono ciągowanie, a nie porównywanie ciągów. overload pragma będzie jednak użyć przeciążony stringification do porównywania ciąg jeśli podasz parametr 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; 
} 

Szczegółowe informacje na temat, dlaczego to działa:

Kiedy wręczył przeciążenia obiekt, operator eq spróbuje wywołać przeciążenie eq. Nie zapewniamy przeciążenia i nie zapewniamy przeciążenia cmp, z którego można automatycznie wygenerować kod eq. Dlatego Perl wyda ten błąd.

Z fallback => 1 enabled, błąd jest pomijany, a Perl zrobi to, co zrobiłby w każdym razie - przymusić argumenty do łańcuchów (które wywołają przeciążenie przez sznurowanie lub inną magię) i porównać je.