为了更简洁地写,而不是这样做:
test_value = method_call_that_might_return_nil()
if test_value
do_something_with test_value
end
我一直在条件中分配:
if test_value = method_call_that_might_return_nil()
do_something_with test_value
end
这是不好的风格?更简洁的语法:
do_something_with test_value if test_value = method_call_that_might_return_nil()
根据Matz(in another SO question)的说法,不允许,如http://redmine.ruby-lang.org/issues/show/1141所述,并且将在1.9中保持这种状态。
鉴于分配和比较可能存在混淆,这是否会使代码难以阅读?
答案 0 :(得分:30)
It is explicitly GOOD style to use assignments in conditionals. If you do so, wrap the condition in parentheses.
# Bad
if value = Settings.get('test_setting')
perform_action(value)
end
# Okay, but uncommon and verbose
value = Settings.get('test_setting')
if value
perform_action(value)
end
# Good
if (value = Settings.get('test_setting'))
perform_action(value)
end
答案 1 :(得分:28)
一个有点普遍的习惯用法是使用and
,它看起来像这样:
tmp = method_call_that_might_return_nil and do_something_with tmp
另一种可能性是明确地调用#nil?
,这样意图就会变得更加清晰;特别是很明显你实际上意味着分配而不是比较:
unless (tmp = method_call_that_might_return_nil).nil?
do_something_with tmp
end
答案 2 :(得分:8)
简洁代码不一定是更好的代码。当Concision改进了从作者到未来维护者的预期代码行为的通信时,它很有用。我认为我们中的很多人都来自于我们在if
块中意外分配的背景(当我们想要进行相等比较时),我们更喜欢样式,其中绝对清楚的是赋值是指,而不是比较。已经提到的.nil?
成语具有该属性,并且我认为它比在if
条件内具有明确赋值更清晰。但实际上,我没有看到为分配提供额外代码的危害。
答案 3 :(得分:5)
执行此操作的函数式编程方法是使用andand
。这是一种链接方法调用的可读方式,因此中间的nil会阻止链。所以你的例子就像:
method_call_that_might_return_nil.andand.tap {|obj| do_something_with obj}
## or, in the common case: ##
method_call_that_might_return_nil.andand.do_something
答案 4 :(得分:3)
是的,我认为由于分配和比较之间可能存在混淆,这种风格很糟糕。分配然后进行测试只需要一行,并且它避免让将来认为这是一个错误并修补它以使用==
。
答案 5 :(得分:2)
C程序员做了很多。我不认为Ruby中有任何问题,只要它清楚发生了什么。
答案 6 :(得分:1)
我认为没关系。在条件中对赋值的厌恶来自于在键入时知道错过的键击==将比较转换为非预期的赋值。在某种情况下使用分配的风格禁止使得这种事故在眼睛中很突出(有时候对于语言而言,如在C中,如果在某种情况下遇到分配,可以使许多编译器发出警告)。另一方面,测试也使这些事故脱颖而出。如果您的代码完全被测试所覆盖,您可以考虑放弃此类禁令。
答案 7 :(得分:0)
由于警告,在 if
子句中执行赋值有一种很刺鼻的气味。如果您确实要处理 else
情况,那么 case ... in ...
模式匹配可以提供一些东西:
case method_call_that_might_return_nil
in nil
# handle nil case
in test_value # pattern match to a new variable
# handle non-nil case with return value of method assigned to test_value
end
或者...
case method_call_that_might_return_nil
in test_value if test_value # pattern match to a new variable if not nil
# handle non-nil case with return value of method assigned to test_value
else
# handle nil case
end