2015-09-21 2 views
1

Я пытаюсь исключить :: Класс в первый раз и что-то, что меня удивило, это то, что объекты Exception :: Class оцениваются как true при возврате из функции. Не следует, чтобы значение по умолчанию было противоположным.Должно исключение :: Объекты класса оцениваются как false в булевом контексте

Я знаю, что я могу изменить это с перегрузкой, но мне интересно, если это хорошая идея

sub gethtml{ 
    return MyException->new(error => 'some error'); 
} 
my $response = &gethtml 

if($response){ 
    #do something with the html 
} 
else{ 
    #something went wrong check if it's an exception object 
} 
+0

Почему вы ожидаете, что они лжецы? Вы путаете их с возвратом ложных за неудачу? – Schwern

+0

@Schwern Я добавил код на вопрос. Я хочу, чтобы у меня была возможность остановить функцию и сказать, что кто-то поступил неправильно, не убив всю программу. по какой-то причине я, хотя и объект исключения оценил бы false – user2348668

ответ

3

Вы путаете исключения с возвратом ложное значение, чтобы указать ошибку.

Часть исключений состоит в том, что они предоставляют свой собственный канал для указания ошибки. Это оставляет return бесплатным и возвращает допустимые значения. Нет необходимости проверять наличие ложных или специальных объектов или выполнять любую проверку на наличие ошибок в каждой функции. Это все поймали и разобрались в конце блока.

Если вы вернете объект исключения, он побеждает точку; они не исключение, они всего лишь коды ошибок.

Чтобы воспользоваться исключениями, код в вашем примере должно быть написано так:

sub get_html { 
    ...try to get the html... 

    return $html if defined $html; 

    MyException->throw(error => 'some error'); 
} 

eval { 
    my $html = get_html; 
    # do something with $html; 
} 
if (my $e = Exception::Class->caught()) { 
    ...deal with the error... 
} 

Это может быть немного симпатичнее с Try::Tiny.

Это имеет смысл, когда вам нужно сделать много вещей, которые могут привести к ошибке, например, к путу файлов, сетевых или баз данных. Изучите такие модули, как autodie и Path::Tiny, как это работает.

2

Нельзя создать его с new и вернуть его. Они имеют метод throw, который автоматически выполняет функцию конструктора и die.

use strict; 
use warnings; 
use Exception::Class qw(InputException HTTPException); 
use Try::Tiny; 

sub get_html { 
    my ($url) = @_; 

    # input validation 
    InputException->throw(error => 'no URL') unless $url; 

    my $res = $ua->get($url); 
    if ($res->is_success) { 
    # do more stuff with $res; 
    } else { 
    HTTPException->throw(error => 'request failed');  
    } 
} 

# ... later 

my $url; 
try { 
    get_html($url); 
} catch { 
    # handle the error which is in $_ 
    if ($_->isa('InputException')) { 
    print "You need to supply a URL"; 
    } elsif ($_->isa('HTTPException')) { 
    print "Could not fetch the HTML because the HTTP request failed.\n"; 
    print "But I am not telling you why."; 
    } 
} 

Вы можете пойти и catch (использовать Try::Tiny для этого), или просто обернуть его в Eval. Но в основном эти исключения являются простыми объектами. Они предназначены как возвращаемое значение die и их выбрасывают, поэтому нет необходимости возвращать их в любом месте.

После того, как программа замирает, все области действия стека вызовов выходят принудительно, пока вы не окажетесь в блоке eval (что и делает catch). Там вы можете справиться с ошибкой. И поскольку эта ошибка является объектом, вы можете с ней притворяться.

+--------------------------------------------------------------------+   
| sub {                |   
| +----------------------------------------------------------------+ |   
| | if() {              | |   
| | +------------------------------------------------------------+ | |   
| | | foo:: sub {            | | |   
| | | +--------------------------------------------------------+ | | |   
| | | | catch {            | | | |   
| | | | +----------------------------------------------------+ | | | |   
| | | | | doo_stuff:: sub {         | | | | |   
| | | | | +------------------------------------------------+ | | | | |   
| | | | | |            | | | | | |   
| | | | | | MyException->throw ==> die $obj +---------------------------------+ 
| | | | | | do_more_stuff(); # never executed    | | | | | |   | 
| | | | | |            | | | | | |   | 
| | | | | +------------------------------------------------+ | | | | |   | 
| | | | +----------------------------------------------------+ | | | |   | 
| | | |              | | | |   | 
| | | | handle_exception_in_catch($_)  <---------------------------------+ 
| | | | # (in Try::Tiny the exception ends up in $_)   | | | |   
| | | |              | | | |   
| | | +--------------------------------------------------------+ | | |   
| | +------------------------------------------------------------+ | |   
| +----------------------------------------------------------------+ |   
+--------------------------------------------------------------------+   

Смотрите также Exception::Class документы.


Если смешать исключения и регулярные die или Carpcroak звонков, вам придется делать много проверки, если материал благословляется перед использованием ->isa. Safe::Isa пригодится здесь.

use strict; 
use warnings; 
use Exception::Class qw(InputException HTTPException); 
use Try::Tiny; 
use Safe::Isa; 

sub get_html { 
    my ($url) = @_; 

    # input validation 
    InputException->throw(error => 'no URL') unless $url; 

    my $res = $ua->get($url); 
    if ($res->is_success) { 
    # do more stuff with $res; 
    die "There is no answer in this HTML" if $res->decoded_content !~ m/42/; 
    } else { 
    HTTPException->throw(error => 'request failed');  
    } 
} 

С помощью этого кода, то $_->isa('...') взорвется, потому что в случае die вызова $_ не является объект, и вы не можете вызвать метод isa на качестве неблагословленных ссылок (или не ссылки).Safe :: Isa предоставляет $_isa, который проверяет это первым и в противном случае просто возвращает false.

my $url; 
try { 
    get_html($url); 
} catch { 
    # handle the error which is in $_ 
    if ($_->$_isa('InputException')) { 
    print "You need to supply a URL"; 
    } elsif ($_->$_isa('HTTPException')) { 
    print "Could not fetch the HTML because the HTTP request failed.\n"; 
    print "But I am not telling you why."; 
    } 
} 

Для получения дополнительной информации о том, как это работает, см mst's talk You did what?

+1

Вы должны проверять исключения по их классу, а не по их сообщению. Я бы порекомендовал 'use Exception :: Class ('InputException');', 'InputException-> throw (error => 'no URL')' и 'if $ _-> isa ('InputException')'. – Schwern

+0

Действительно. Я был ленивым @Swwern;) – simbabque

Смежные вопросы