2013-02-27 78 views
3

我无法确定什么是错用下面的Ruby内联救援码为什么a = b解救一个错误但救援stmt不是?

def test_check() 
p "first st" 
t = 5 * lsdj rescue return false 
p "second" 
end 

p test_check 

这是给一个错误消息syntax error, unexpected kFALSE, expecting kEND 但如果我删除赋值语句它会正常工作(返回false)。

def test_check() 
    p "first st" 
    5 * lsdj rescue return false 
    p "second" 
    end 

如果出了什么问题红宝石内嵌救援的正确语法是什么?

+0

+1。一个非常好的问题。人们会希望修饰符规则在两种情况下都能得到相同的解析,并且对此的回答会遇到很多关于Ruby为什么会这样的问题。也许只有马茨知道完整的答案,但我已经在下面贡献了我的理解。 – DigitalRoss 2013-02-27 22:52:58

回答

12

嵌入式rescue在分配中使用它时不会将语句当作参数1,2 - 它只是希望得到一个表达式的值,以获取它被救出的情况。

但要小心,你认为这会返回什么?

def q 
    return 5 * lsdj rescue false 
    true 
end 

假,返回。这样做,而不是救援只适用于表达式。

def q 
    return (5 * lsdj rescue false) 
    true 
end 

此人返回false。


注意事项:
1.这实际上是一个很好的问题。重述:
          为什么A = B救援语句一个错误,但语句救援语句是不是?
而肤浅的答案是,在分配的情况下RHS和救援语句是ARG非终结符在Ruby语法,而不是完整的语句,而在声明的情况下的语法简单的抢救后解析一个完整的语句规则。这只是它定义的方式。现在,如果你问为什么呢? ......好吧...... Ruby的复杂语法生活在yacc(1)有能力的边缘。在我看来,在很多情况下,Matz详细阐述了在某些情况下究竟会接受什么,而不仅仅是使用单个非终端,如expr,我想象的原因是保留语法LALR(1)并将不可避免的shift/reduce conflicts限制在可容忍的范围内。 Check out parse.y在Ruby源码分发中进行了一个有趣的阅读。
2.这里是一个例子:def q; (t = 5 * lsdj) rescue return false; true; end
这可以像你想的那样工作,因为它只是恰好符合其他语法规则。我听说为了支持诗歌模式存在一些这些限制。

+1

我搜索了很多文档,但是找不到任何好的文档。最后的解释很好,谢谢@DigitalRoss。 – 2013-03-01 12:23:27

2

您的代码将被解释为:

def test_check() 
p "first st" 
t = (5 * lsdj rescue return) false 
p "second" 
end 

这使得false无效状态图。为了解决这个问题,在圆括号中加上:

def test_check() 
p "first st" 
t = 5 * lsdj rescue (return false) 
p "second" 
end 
+3

为了迂回,具体的问题是救援修饰符的参数(当应用于赋值时)是非终端'arg',并且不能解析以'keyword_return.'开头的语句。但是,添加' (...)'会导致语法解析一个'primary'表达式,它恰好包含* return *语句。 – DigitalRoss 2013-02-27 18:21:23