“Sair de loops aninhados” é uma necessidade comum em muitas linguagens de programação. Além disso o gotoem C / C ++ como @docwhat mencionou, Java tem marcado ruptura e continuar . (Python também tem uma proposta rejeitada para isso).
pegar / arremessar não é o mesmo que levantar / resgatar. catch / throw permite que você saia rapidamente dos blocos de volta a um ponto em que uma captura é definida para um símbolo específico;
Curioso para saber ... Lendo isso de um iPad, não podemos testá-los no 1.9, mas alguns desses truques não são mais válidos nas versões recentes do ruby, certo?
Denis de Bernardy
12
Também vale a pena conhecer: raiseé muito caro. thrownão é. Pense throwcomo usar gotopara sair de um loop.
raise, fail, rescue, E ensurelidar com erros , também conhecido como exceções
throwe catchsão fluxo de controle
Diferentemente de outros idiomas, o throw e catch de Ruby não são usados para exceções. Em vez disso, eles fornecem uma maneira de encerrar a execução mais cedo, quando nenhum trabalho adicional é necessário. (Grimm, 2011)
O término de um único nível de fluxo de controle, como um whileloop, pode ser feito com um simples return. É possível encerrar muitos níveis de fluxo de controle, como um loop aninhado throw.
Embora o mecanismo de exceção de aumento e resgate seja ótimo para abandonar a execução quando algo der errado, às vezes é bom poder pular de uma construção profundamente aninhada durante o processamento normal. É aqui que o catch and throw é útil. (Thomas e Hunt, 2001)
raise/ rescuesão os análogos mais próximos da construção throw/ que catchvocê conhece de outras linguagens (ou da raise/ do Python except). Se você encontrou uma condição de erro e a encontrou throwem outro idioma, deve fazê-lo raiseem Ruby.
Ruby throw/ catchpermite interromper a execução e subir na pilha procurando por catch(como raise/ rescuefaz), mas não é realmente destinado a condições de erro. Ele deve ser usado raramente e existe apenas para quando o catchcomportamento "subir a pilha até encontrar um correspondente " faz sentido para um algoritmo que você está escrevendo, mas não faria sentido pensar nele throwcomo correspondente a um erro doença.
As diferenças comportamentais concretas entre eles incluem:
rescue Fooresgatará instâncias de Fooinclusão de subclasses de Foo. catch(foo)só pegará o mesmo objetoFoo . Não apenas você não pode passar catchum nome de classe para capturar instâncias, como também não fará comparações de igualdade. Por exemplo
catch("foo")do
throw "foo"end
lhe dará um UncaughtThrowError: uncaught throw "foo"(ou um ArgumentErrornas versões do Ruby anteriores à 2.2)
Várias cláusulas de resgate podem ser listadas ...
begin
do_something_error_prone
rescueAParticularKindOfError# Insert heroism here.rescue
write_to_error_log
raise
end
enquanto vários catches precisam ser aninhados ...
catch :foo do
catch :bar do
do_something_that_can_throw_foo_or_bar
endend
Um bare rescueé equivalente rescue StandardErrore é uma construção idiomática. Um "nu catch", como catch() {throw :foo}, nunca vai pegar nada e não deve ser usado.
Boa explicação, mas implora a pergunta: por que diabos eles projetariam o aumento em ruby = throw em outro idioma? e também inclua throw but it! = throw em outros idiomas. Eu não posso ver a sua lógica original lá
wired00
@ wired00 ( Encolho de ombros.) Concordo que parece bastante excêntrico em comparação com outros idiomas populares hoje em dia.
Mark Amery
2
@ wired00: Tem sido chamado "levantando" uma exceção desde os primeiros experimentos com manipulação de erros estruturados na década de 1960, é chamado "levantando" uma exceção nos artigos seminais que inventaram a forma moderna de tratamento de exceções, é chamado "levantando" uma exceção em Lisps e Smalltalks, que foram algumas das principais inspirações para Ruby, e é chamado "levantando" uma exceção ou "levantando" uma interrupção no hardware, onde o conceito existia antes do conceito de "programação" idioma "existia. A pergunta deveria ser: por que essas outras línguas mudaram isso?
Jörg W Mittag
@ MarkAmery: Lembre-se de que muitas dessas "outras línguas populares" são mais jovens que Ruby ou pelo menos contemporâneas. Portanto, a pergunta deveria ser: por que essas outras línguas não seguiram Ruby (e Smalltalk e Lisp, hardware e literatura).
Jörg W Mittag
@ JörgWMittag Interessante - você me inspirou a fazer uma pequena pesquisa histórica. C ++ teve a noção de "lançar" uma exceção anos antes de Ruby aparecer, e por english.stackexchange.com/a/449209/73974 o termo realmente remonta aos anos 70 ... então acho que ainda podemos criticar Ruby por tomando terminologia estabelecida e usando-a para significar algo completamente diferente.
goto
em C / C ++ como @docwhat mencionou, Java tem marcado ruptura e continuar . (Python também tem uma proposta rejeitada para isso).Respostas:
Eu acho que http://hasno.info/ruby-gotchas-and-caveats tem uma explicação decente da diferença:
fonte
raise
é muito caro.throw
não é. Pensethrow
como usargoto
para sair de um loop.raise
,fail
,rescue
, Eensure
lidar com erros , também conhecido como exceçõesthrow
ecatch
são fluxo de controleO término de um único nível de fluxo de controle, como um
while
loop, pode ser feito com um simplesreturn
. É possível encerrar muitos níveis de fluxo de controle, como um loop aninhadothrow
.Referências
fonte
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, copiando alguns exemplos de código da postagem do blog enquanto eu vou:
raise
/rescue
são os análogos mais próximos da construçãothrow
/ quecatch
você conhece de outras linguagens (ou daraise
/ do Pythonexcept
). Se você encontrou uma condição de erro e a encontrouthrow
em outro idioma, deve fazê-loraise
em Ruby.Ruby
throw
/catch
permite interromper a execução e subir na pilha procurando porcatch
(comoraise
/rescue
faz), mas não é realmente destinado a condições de erro. Ele deve ser usado raramente e existe apenas para quando ocatch
comportamento "subir a pilha até encontrar um correspondente " faz sentido para um algoritmo que você está escrevendo, mas não faria sentido pensar nelethrow
como correspondente a um erro doença.Para que o catch and throw é usado no Ruby? oferece algumas sugestões sobre bons usos do
throw
/catch
construct.As diferenças comportamentais concretas entre eles incluem:
rescue Foo
resgatará instâncias deFoo
inclusão de subclasses deFoo
.catch(foo)
só pegará o mesmo objetoFoo
. Não apenas você não pode passarcatch
um nome de classe para capturar instâncias, como também não fará comparações de igualdade. Por exemplolhe dará um
UncaughtThrowError: uncaught throw "foo"
(ou umArgumentError
nas versões do Ruby anteriores à 2.2)Várias cláusulas de resgate podem ser listadas ...
enquanto vários
catch
es precisam ser aninhados ...Um bare
rescue
é equivalenterescue StandardError
e é uma construção idiomática. Um "nucatch
", comocatch() {throw :foo}
, nunca vai pegar nada e não deve ser usado.fonte