例如,当我在我的代码上运行ReSharper时:
if (some condition)
{
Some code...
}
ReSharper给了我上面的警告(反转“if”语句以减少嵌套),并建议以下更正:
if (!some condition) return;
Some code...
我想知道为什么这样更好。我一直认为在方法中间使用“return”是有问题的,有点像“goto”。
例如,当我在我的代码上运行ReSharper时:
if (some condition)
{
Some code...
}
ReSharper给了我上面的警告(反转“if”语句以减少嵌套),并建议以下更正:
if (!some condition) return;
Some code...
我想知道为什么这样更好。我一直认为在方法中间使用“return”是有问题的,有点像“goto”。
当前回答
在性能方面,这两种方法之间没有明显的区别。
但是编码不仅仅关乎性能。清晰性和可维护性也非常重要。而且,在这种情况下,它不会影响性能,这是唯一重要的事情。
关于哪种方法更可取,存在着相互竞争的思想流派。
一种观点是其他人已经提到的观点:第二种方法减少了嵌套级别,从而提高了代码的清晰度。这在命令式风格中是很自然的:当你没有什么事情要做的时候,你不妨早点回来。
从函数式风格的角度来看,另一种观点认为一个方法应该只有一个出口点。函数式语言中的一切都是表达式。所以if语句必须总是有一个else子句。否则if表达式并不总是有值。所以在函数式风格中,第一种方法更自然。
其他回答
只在函数结束时返回的想法来自语言支持异常之前的时代。它使程序能够依赖于能够将清理代码放在方法的末尾,然后确保它会被调用,而其他程序员不会在方法中隐藏导致跳过清理代码的返回值。跳过清理代码可能导致内存或资源泄漏。
然而,在支持异常的语言中,它不提供这样的保证。在支持异常的语言中,任何语句或表达式的执行都可能导致导致方法结束的控制流。这意味着清理必须通过使用finally或使用关键字来完成。
不管怎样,我想说的是,我认为很多人引用了“只在方法末尾返回”的指导原则,却不理解为什么它是一件好事,而减少嵌套以提高可读性可能是一个更好的目标。
我的想法是“在函数中间”的返回不应该那么“主观”。 原因很简单,以下面的代码为例:
function do_something( data ){ if (!is_valid_data( data )) return false; do_something_that_take_an_hour( data ); istance = new object_with_very_painful_constructor( data ); if ( istance is not valid ) { error_message( ); return ; } connect_to_database ( ); get_some_other_data( ); return; }
也许第一个“回报”不是那么直观,但这是真正的储蓄。 有太多关于干净代码的“想法”,只是需要更多的实践来摆脱他们“主观的”坏想法。
多个返回点在C中是一个问题(在较小程度上是c++),因为它们迫使您在每个返回点之前复制清理代码。对于垃圾收集,try |最终构造并使用块,您真的没有理由害怕它们。
归根结底,这取决于你和你的同事觉得什么更容易阅读。
就我个人而言,我倾向于只有一个退出点。如果您保持方法的简短和切中要害,这很容易实现,并且它为下一个处理您的代码的人提供了可预测的模式。
eg.
bool PerformDefaultOperation()
{
bool succeeded = false;
DataStructure defaultParameters;
if ((defaultParameters = this.GetApplicationDefaults()) != null)
{
succeeded = this.DoSomething(defaultParameters);
}
return succeeded;
}
如果您只是想在函数退出之前检查函数中某些局部变量的值,这也是非常有用的。您所需要做的就是在最终返回值上放置一个断点,并保证能够命中它(除非抛出异常)。
表演分为两部分。在软件处于生产状态时,您需要性能,但在开发和调试时也需要性能。开发人员最不想做的事情就是“等待”一些微不足道的事情。最后,在启用优化的情况下编译该代码将生成类似的代码。所以知道这些在两种情况下都有好处的小技巧是很好的。
问题中的情况很清楚,ReSharper是正确的。不是嵌套if语句,也不是在代码中创建新的作用域,而是在方法的开头设置一个明确的规则。它增加了可读性,更容易维护,并减少了人们必须筛选的规则数量。