问题
According to The Ruby Programming Language p.164.
If a
begin
statement doesn't propagate an exception, then the value of the statement is the value of the last expression evaluated in thebegin
,rescue
orelse
clauses.
But I found this behavior consistent with the begin block together with else clause and ensure clause.
Here is the example code:
def fact (n)
raise "bad argument" if n.to_i < 1
end
value = begin
fact (1)
rescue RuntimeError => e
p e.message
else
p "I am in the else statement"
ensure
p "I will be always executed"
p "The END of begin block"
end
p value
The output is:
"I am in the else statement"
"I will be always executed"
"The END of begin block"
"I am in the else statement"
[Finished]
The value
is evaluated to the else clause. This is inconsistent behavior as the ensure clause is the last statement executed.
Could someone explain what's happening within the begin block?
回答1:
I'd interpret the goal of the begin/rescue/else/end
block as:
- Execute the code in the
begin
section, and then the code in theelse
section. - If something goes wrong in the
begin
section, execute therescue
section instead of theelse
section.
So either the rescue
section or the else
section will be executed after trying the begin
section; so it makes sense that one of them will be used as the whole block's value.
It's simply a side effect that the ensure
section will always be executed.
val = begin
p "first"; "first"
rescue => e
p "fail"; "fail"
else
p "else"; "else"
ensure
p "ensure"; "ensure"
end
val # => "else"
# >> "first"
# >> "else"
# >> "ensure"
But:
val = begin
p "first"; "first"
raise
rescue => e
p "fail"; "fail"
else
p "else"; "else"
ensure
p "ensure"; "ensure"
end
val # => "fail"
# >> "first"
# >> "fail"
# >> "ensure"
回答2:
I'm just guessing here, but as the purpose of a ensure block is to finalize any resources that may remain open (cleanup in other words), and so it makes sense that the logical value should be the result of the else statement. It makes sense to me that it is by design.
回答3:
In this case the begin
block is just a way of defining a section for which you may want to do exception handling.
Remember that else
in this case runs if no exceptions occur, and ensure
will run regardless of exceptions or a lack thereof.
来源:https://stackoverflow.com/questions/9687579/how-is-the-value-of-a-begin-block-determined