'如果没有'或'不在Ruby工作

时间:2015-04-25 16:52:05

标签: ruby

我在Ruby中有这个代码:

if @pass.nil?
        badpass(@nick)
elsif not clt.correctpassword?(@nick, @pass)
        badpass(@nick)

我想把它浓缩成一行,所以我尝试把它写成:

if not clt.correctpassword?(@nick, @pass) or @pass.nil?
        badpass(@nick)

但是,badpass(@nick)在任何一种情况下都不会被触发,而在上面两个例子中它都适用。

为什么会这样?

2 个答案:

答案 0 :(得分:4)

在修订后的代码中,测试的顺序与原始测试的顺序相反。好像你写过:

if not clt.correctpassword?( @nick, @pass )
    badpass( @nick )
elsif @pass.nil?
    badpass( @nick )
end

将测试按照与原始测试相同的顺序进行测试,它将像原始测试一样工作:

if @pass.nil? or not clt.correctpassword?( @nick, @pass )
    badpass( @nick )
end

请记住,与许多其他语言一样,Ruby使用short circuit evaluation作为逻辑运算符andor&&||。这意味着它首先计算运算符左侧的表达式,然后仅在需要时计算运算符右侧的表达式。

顺便说一句,很多Rubyist会用这种方式写它:

badpass( @nick ) if @pass.nil? or not clt.correctpassword?( @nick, @pass )

那是同样的事情;它只是你喜欢哪种风格的问题。

如果.correctpassword?方法是您可以修改的代码,那么另一个不错的选择是在该方法的开头添加一个nil测试。事实上,您也可以在 nickpass上测试nil:

def correctpassword?( nick, pass )
    return false if nick.nil? or pass.nil?
    ... the rest of your code here ...
end

然后,当您调用此方法时,您只需使用:

if not clt.correctpassword?( @nick, @pass )
    badpass( @nick )
end

或这个简单的代码:

badpass( @nick ) unless clt.correctpassword?( @nick, @pass )

答案 1 :(得分:3)

您不应在条件中使用andornot。它们用于控制流程,它们会在条件下导致precedence问题。

让我们改变您的代码:

if @pass.nil?
  badpass(@nick)
elsif not clt.correctpassword?(@nick, @pass)
  badpass(@nick)
end

让它更像Ruby:

if !@pass
  badpass(@nick)
elsif !clt.correctpassword?(@nick, @pass)
  badpass(@nick)
end

结合条件:

if !@pass || !clt.correctpassword?(@nick, @pass)
  badpass(@nick)
end

简单条件(De Morgan's law

if !(@pass && clt.correctpassword?(@nick, @pass))
  badpass(@nick)
end

甚至更像Ruby:

badpass(@nick) unless @pass && clt.correctpassword?(@nick, @pass)

我同意@MichaelGeary你应该检查@pass方法中是否存在correctpassword? ......