我在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)
在任何一种情况下都不会被触发,而在上面两个例子中它都适用。
为什么会这样?
答案 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作为逻辑运算符and
,or
,&&
和||
。这意味着它首先计算运算符左侧的表达式,然后仅在需要时计算运算符右侧的表达式。
badpass( @nick ) if @pass.nil? or not clt.correctpassword?( @nick, @pass )
那是同样的事情;它只是你喜欢哪种风格的问题。
如果.correctpassword?
方法是您可以修改的代码,那么另一个不错的选择是在该方法的开头添加一个nil测试。事实上,您也可以在 nick
和pass
上测试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)
您不应在条件中使用and
,or
或not
。它们用于控制流程,它们会在条件下导致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?
......