Where are catch and throw useful in Ruby?

前端 未结 4 585
囚心锁ツ
囚心锁ツ 2021-01-17 19:20

I really don\'t see a sane use for these. There is already rescue and raise, so why the need for throw and catch? It seem

相关标签:
4条回答
  • 2021-01-17 19:35

    Note: It looks like a few things have changed with catch/throw in 1.9. This answer applies to Ruby 1.9.

    A big difference is that you can throw anything, not just things that are derived from StandardError, unlike raise. Something silly like this is legal, for example:

    throw Customer.new
    

    but it's not terribly meaningful. But you can't do:

    irb(main):003:0> raise Customer.new
    TypeError: exception class/object expected
        from (irb):3:in `raise'
        from (irb):3
        from /usr/local/bin/irb:12:in `<main>'
    
    0 讨论(0)
  • 2021-01-17 19:38

    They can be really useful in simplifying DSLs for end users by passing control out of the DSL without the need for complex case / if statements

    I have a Ruby app which allows users to extend it via an internal DSL. Some of the functions in the DSL need to return control to specific parts of my application. Let's take a simple example. Suppose the user is developing a simple extension concerning dates

    if today is a holiday then
       do nothing
    end
    
    week_of_year = today.week.number
    
    if week_of_year < 10 then
    
    ...
    

    The do nothing bit triggers a throw which passes control out of the exec statement and back to me.

    Rather than continuing to execute the DSL, on some condition, we want it to exit and hand control back to my application. Now you could get the user to use lots of embedded if statements and have the DSL end naturally but that just obscures what the logic is trying to say.

    Throw really is a goto which is 'considered dangerous' but damn it sometimes they are the best solution.

    0 讨论(0)
  • 2021-01-17 19:40

    It's basically a goto, and slightly more akin to a call/cc, except that the control flow is wired up implicitly by name instead of explicitly as a parameter. The difference between throw/catch and raise/rescue is that the former is intended to be used for control flow instead of only exceptional situations, and it doesn't waste time putting together a stack trace.

    Sinatra uses throw/catch for HTTP error codes, where a handler can use throw to cede control to the Sinatra library in a structured way. Other sorts of HTTP frameworks use exceptions, or by returning a different class of response, but this lets Sinatra (for example) try another request handler after catching it.

    0 讨论(0)
  • 2021-01-17 20:01

    The difference between the two is that you can only 'raise' exceptions but can 'throw' anything (1.9). Other than that, they should be interchangeable, that is, it should be possible to rewrite one with another, just like the example given by @john-feminella.

    0 讨论(0)
提交回复
热议问题