Qual é a diferença entre levantar exceções e lançar exceções em Ruby?
Pergunta
Ruby tem dois mecanismos de exceções diferentes:Lançar/Pegar e Levantar/Resgatar.
Por que temos dois?
Quando você deve usar um e não o outro?
Solução
Eu penso http://hasno.info/ruby-gotchas-and-caveats tem uma explicação decente da diferença:
pegar/arremessar não é o mesmo que levantar/resgatar.catch/throw permite que você saia rapidamente dos blocos de volta a um ponto onde um catch é definido para um símbolo específico, raise Rescue é o verdadeiro tratamento de exceção que envolve o objeto Exception.
Outras dicas
raise
,fail
,rescue
, eensure
lidar erros, também conhecido como exceçõesthrow
ecatch
são controle de fluxo
Ao contrário de outros idiomas, o arremesso e a captura de Ruby não são usados para exceções.Em vez disso, eles fornecem uma maneira de encerrar a execução cedo, quando não for necessário mais trabalho.(Grimm, 2011)
Terminar um único nível de fluxo de controle, como um while
loop, pode ser feito com um simples return
.Terminar muitos níveis de fluxo de controle, como um loop aninhado, pode ser feito com throw
.
Embora o mecanismo de exceção de aumento e resgate seja ótimo para abandonar a execução quando as coisas dão errado, às vezes é bom poder saltar de alguma construção profundamente aninhada durante o processamento normal.É aqui que pegar e lançar é útil.(Thomas e Hunt, 2001)
Referências
- Grimm, Avdi."Jogue, pegue, levante, resgate ... estou tão confuso!" Blog de Rubylearning.Np, 11 de julho de 2011.Rede.1º de janeiro2012. http://rubylearning.com/blog/2011/07/12/throw-catch-raise-rescue--im-so-confused/.
- Thomas, Dave e Andrew Hunt."Programando Ruby." :O Guia do Programador Pragmático.Np, 2001.Rede.29 de setembro2015. http://ruby-doc.com/docs/ProgrammingRuby/html/tut_exceptions.html.
https://coderwall.com/p/lhkkug/don-t-confuse-ruby-s-throw-statement-with-raise oferece uma excelente explicação que duvido que possa melhorar.Para resumir, vou pegando alguns exemplos de código da postagem do blog:
raise
/rescue
são os análogos mais próximos dothrow
/catch
construção com a qual você está familiarizado de outras linguagens (ou do Pythonraise
/except
).Se você encontrou uma condição de erro e gostariathrow
sobre isso em outro idioma, você deveraise
em Rubi.Rubi
throw
/catch
permite interromper a execução e subir na pilha em busca de umcatch
(comoraise
/rescue
faz), mas não se destina realmente a condições de erro.Deve ser usado raramente e existe apenas para quando "subir na pilha até encontrar um arquivo correspondente".catch
"o comportamento faz sentido para um algoritmo que você está escrevendo, mas não faria sentido pensar nothrow
como correspondendo a uma condição de erro.Para que serve pegar e lançar em Ruby? oferece algumas sugestões sobre bons usos do
throw
/catch
construir.
As diferenças comportamentais concretas entre eles incluem:
rescue Foo
resgatará instâncias deFoo
incluindo subclasses deFoo
.catch(foo)
só vai pegar o mesmo objeto,Foo
.Não só você não pode passarcatch
um nome de classe para capturar instâncias dela, mas nem mesmo fará comparações de igualdade.Por exemplocatch("foo") do throw "foo" end
lhe dará um
UncaughtThrowError: uncaught throw "foo"
(ou umArgumentError
em versões de Ruby anteriores a 2.2)Várias cláusulas de resgate podem ser listadas...
begin do_something_error_prone rescue AParticularKindOfError # Insert heroism here. rescue write_to_error_log raise end
enquanto múltiplo
catch
es precisam ser aninhados ...catch :foo do catch :bar do do_something_that_can_throw_foo_or_bar end end
Um nu
rescue
é equivalente arescue StandardError
e é uma construção idiomática.Um "nucatch
", comocatch() {throw :foo}
, nunca pegará nada e não deve ser usado.