为什么我要“反转”如果“?减少嵌套的语句”?

发布于 2024-12-20 05:00:34 字数 452 浏览 5 评论 0原文

当我在代码上运行 ReSharper 时,例如:

if (some condition)
{
    Some code...            
}

ReSharper 给了我上述警告 (Invert " if”语句以减少嵌套),并建议进行以下更正:

if (!some condition) return;
Some code...

我想了解为什么这样更好。我一直认为在方法中间使用“return”是有问题的,有点像“goto”。

When I ran ReSharper on my code, for example:

if (some condition)
{
    Some code...            
}

ReSharper gave me the above warning (Invert "if" statement to reduce nesting), and suggested the following correction:

if (!some condition) return;
Some code...

I would like to understand why that's better. I always thought that using "return" in the middle of a method problematic, somewhat like "goto".

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(25

帅的被狗咬 2024-12-27 05:00:34

它不仅美观,而且还减少了方法内的最大嵌套级别。这通常被认为是一个优点,因为它使方法更容易理解(事实上,许多 静态 分析 工具提供了对此的衡量标准,作为代码质量的指标之一)。

另一方面,它也使你的方法有多个退出点,而另一群人认为这是禁忌。

就我个人而言,我同意 ReSharper 和第一组的观点(在一种有例外的语言中,我发现讨论“多个退出点”很愚蠢;几乎任何东西都可能抛出,因此所有方法中都有许多潜在的退出点)。

关于性能:在每种语言中,两个版本应该是等效的(如果不是在 IL 级别,那么当然是在代码抖动结束之后)。理论上,这取决于编译器,但实际上当今任何广泛使用的编译器都能够处理比这更高级的代码优化情况。

It is not only aesthetic, but it also reduces the maximum nesting level inside the method. This is generally regarded as a plus because it makes methods easier to understand (and indeed, many static analysis tools provide a measure of this as one of the indicators of code quality).

On the other hand, it also makes your method have multiple exit points, something that another group of people believes is a no-no.

Personally, I agree with ReSharper and the first group (in a language that has exceptions I find it silly to discuss "multiple exit points"; almost anything can throw, so there are numerous potential exit points in all methods).

Regarding performance: both versions should be equivalent (if not at the IL level, then certainly after the jitter is through with the code) in every language. Theoretically this depends on the compiler, but practically any widely used compiler of today is capable of handling much more advanced cases of code optimization than this.

怎樣才叫好 2024-12-27 05:00:34

在方法中间返回并不一定是坏事。如果立即返回可以使代码的意图更清晰,那么可能会更好。例如:

double getPayAmount() {
    double result;
    if (_isDead) result = deadAmount();
    else {
        if (_isSeparated) result = separatedAmount();
        else {
            if (_isRetired) result = retiredAmount();
            else result = normalPayAmount();
        };
    }
     return result;
};

在这种情况下,如果_isDead为true,我们可以立即退出该方法。以这种方式构建它可能会更好:

double getPayAmount() {
    if (_isDead)      return deadAmount();
    if (_isSeparated) return separatedAmount();
    if (_isRetired)   return retiredAmount();

    return normalPayAmount();
};   

我从 重构目录。这种特定的重构称为:用保护子句替换嵌套条件。

A return in the middle of the method is not necessarily bad. It might be better to return immediately if it makes the intent of the code clearer. For example:

double getPayAmount() {
    double result;
    if (_isDead) result = deadAmount();
    else {
        if (_isSeparated) result = separatedAmount();
        else {
            if (_isRetired) result = retiredAmount();
            else result = normalPayAmount();
        };
    }
     return result;
};

In this case, if _isDead is true, we can immediately get out of the method. It might be better to structure it this way instead:

double getPayAmount() {
    if (_isDead)      return deadAmount();
    if (_isSeparated) return separatedAmount();
    if (_isRetired)   return retiredAmount();

    return normalPayAmount();
};   

I've picked this code from the refactoring catalog. This specific refactoring is called: Replace Nested Conditional with Guard Clauses.

救赎№ 2024-12-27 05:00:34

这有点宗教性的争论,但我同意 ReSharper 的观点,即您应该更喜欢减少嵌套。我相信这超过了函数具有多个返回路径的负面影响。

减少嵌套的关键原因是为了提高代码可读性和可维护性。请记住,许多其他开发人员将来需要阅读您的代码,而缩进较少的代码通常更容易阅读。

先决条件是一个很好的例子,说明可以在函数开始时提前返回。为什么函数其余部分的可读性会受到前置条件检查的影响?

至于从方法多次返回的负面影响 - 调试器现在非常强大,并且很容易找出特定函数返回的确切位置和时间。

函数中有多个返回不会影响维护程序员的工作。

代码可读性差会影响。

This is a bit of a religious argument, but I agree with ReSharper that you should prefer less nesting. I believe that this outweighs the negatives of having multiple return paths from a function.

The key reason for having less nesting is to improve code readability and maintainability. Remember that many other developers will need to read your code in the future, and code with less indentation is generally much easier to read.

Preconditions are a great example of where it is okay to return early at the start of the function. Why should the readability of the rest of the function be affected by the presence of a precondition check?

As for the negatives about returning multiple times from a method - debuggers are pretty powerful now, and it's very easy to find out exactly where and when a particular function is returning.

Having multiple returns in a function is not going to affect the maintainance programmer's job.

Poor code readability will.

说不完的你爱 2024-12-27 05:00:34

正如其他人提到的,不应影响性能,但还有其他考虑因素。除了这些合理的担忧之外,在某些情况下这也可能会让您陷入困境。假设您正在处理double

public void myfunction(double exampleParam){
    if(exampleParam > 0){
        //Body will *not* be executed if Double.IsNan(exampleParam)
    }
}

将其与看似等效的反转进行对比:

public void myfunction(double exampleParam){
    if(exampleParam <= 0)
        return;
    //Body *will* be executed if Double.IsNan(exampleParam)
}

因此,在某些情况下,似乎是正确反转的if可能不是。

As others have mentioned, there shouldn't be a performance hit, but there are other considerations. Aside from those valid concerns, this also can open you up to gotchas in some circumstances. Suppose you were dealing with a double instead:

public void myfunction(double exampleParam){
    if(exampleParam > 0){
        //Body will *not* be executed if Double.IsNan(exampleParam)
    }
}

Contrast that with the seemingly equivalent inversion:

public void myfunction(double exampleParam){
    if(exampleParam <= 0)
        return;
    //Body *will* be executed if Double.IsNan(exampleParam)
}

So in certain circumstances what appears to be a a correctly inverted if might not be.

黎歌 2024-12-27 05:00:34

仅在函数结束时返回的想法来自语言支持异常之前的日子。它使程序能够依赖于能够将清理代码放在方法的末尾,然后确保它会被调用,并且其他程序员不会在方法中隐藏导致跳过清理代码的返回。跳过清理代码可能会导致内存或资源泄漏。

然而,在支持异常的语言中,它不提供这样的保证。在支持异常的语言中,任何语句或表达式的执行都可能导致控制流导致方法结束。这意味着必须通过使用finally或using关键字来完成清理。

无论如何,我想说的是,我认为很多人引用“仅在方法末尾返回”准则,但不理解为什么这样做是一件好事,并且减少嵌套以提高可读性可能是更好的目标。

The idea of only returning at the end of a function came back from the days before languages had support for exceptions. It enabled programs to rely on being able to put clean-up code at the end of a method, and then being sure it would be called and some other programmer wouldn't hide a return in the method that caused the cleanup code to be skipped. Skipped cleanup code could result in a memory or resource leak.

However, in a language that supports exceptions, it provides no such guarantees. In a language that supports exceptions, the execution of any statement or expression can cause a control flow that causes the method to end. This means clean-up must be done through using the finally or using keywords.

Anyway, I'm saying I think a lot of people quote the 'only return at the end of a method' guideline without understanding why it was ever a good thing to do, and that reducing nesting to improve readability is probably a better aim.

月竹挽风 2024-12-27 05:00:34

我想补充一点,那些倒置的 if 有一个名字 - Guard Clause。我会尽可能使用它。

我讨厌阅读开头有 if 的代码,两屏代码,没有其他内容。只需反转 if 并返回即可。这样就没有人会浪费时间滚动。

http://c2.com/cgi/wiki?GuardClause

I'd like to add that there is name for those inverted if's - Guard Clause. I use it whenever I can.

I hate reading code where there is if at the beginning, two screens of code and no else. Just invert if and return. That way nobody will waste time scrolling.

http://c2.com/cgi/wiki?GuardClause

谎言月老 2024-12-27 05:00:34

不仅影响美观,而且还防止代码嵌套。

它实际上可以作为确保您的数据有效的前提条件。

It doesn't only affect aesthetics, but it also prevents code nesting.

It can actually function as a precondition to ensure that your data is valid as well.

故人如初 2024-12-27 05:00:34

这当然是主观的,但我认为它在两点上得到了很大的改进:

  • 现在很明显,如果 condition 成立,您的函数就没有什么可做的。
  • 它使嵌套水平降低。嵌套对可读性的损害比你想象的还要严重。

This is of course subjective, but I think it strongly improves on two points:

  • It is now immediately obvious that your function has nothing left to do if condition holds.
  • It keeps the nesting level down. Nesting hurts readability more than you'd think.
一紙繁鸢 2024-12-27 05:00:34

多个返回点在 C(以及较小程度上的 C++)中是一个问题,因为它们迫使您在每个返回点之前复制清理代码。通过垃圾回收,try | finally 构造和 using 块,你真的没有理由害怕它们。

最终,这取决于您和您的同事认为更容易阅读的内容。

Multiple return points were a problem in C (and to a lesser extent C++) because they forced you to duplicate clean-up code before each of the return points. With garbage collection, the try | finally construct and using blocks, there's really no reason why you should be afraid of them.

Ultimately it comes down to what you and your colleagues find easier to read.

甜中书 2024-12-27 05:00:34

保护子句或前置条件(正如您可能看到的那样)检查是否满足某个条件,然后中断程序的流程。它们非常适合您真正只对 if 语句的一个结果感兴趣的地方。因此,不要说:

if (something) {
    // a lot of indented code
}

如果满足相反的条件,则反转条件并中断

if (!something) return false; // or another value to show your other code the function did not execute

// all the code from before, save a lot of tabs

return 远不如 goto 那么脏。它允许您传递一个值来显示该函数无法运行的其余代码。

您将看到在嵌套条件中应用此方法的最佳示例:

if (something) {
    do-something();
    if (something-else) {
        do-another-thing();
    } else {
        do-something-else();
    }
}

vs:

if (!something) return;
do-something();

if (!something-else) return do-something-else();
do-another-thing();

您会发现很少有人认为第一个更干净,但当然,它完全是主观的。有些程序员喜欢通过缩进了解某些东西在什么条件下运行,而我更愿意保持方法流程线性。

我暂时不会建议预兆会改变你的生活或让你上床,但你可能会发现你的代码更容易阅读。

Guard clauses or pre-conditions (as you can probably see) check to see if a certain condition is met and then breaks the flow of the program. They're great for places where you're really only interested in one outcome of an if statement. So rather than say:

if (something) {
    // a lot of indented code
}

You reverse the condition and break if that reversed condition is fulfilled

if (!something) return false; // or another value to show your other code the function did not execute

// all the code from before, save a lot of tabs

return is nowhere near as dirty as goto. It allows you to pass a value to show the rest of your code that the function couldn't run.

You'll see the best examples of where this can be applied in nested conditions:

if (something) {
    do-something();
    if (something-else) {
        do-another-thing();
    } else {
        do-something-else();
    }
}

vs:

if (!something) return;
do-something();

if (!something-else) return do-something-else();
do-another-thing();

You'll find few people arguing the first is cleaner but of course, it's completely subjective. Some programmers like to know what conditions something is operating under by indentation, while I'd much rather keep method flow linear.

I won't suggest for one moment that precons will change your life or get you laid but you might find your code just that little bit easier to read.

时光暖心i 2024-12-27 05:00:34

在性能方面,两种方法之间不会有明显差异。

但编码不仅仅关乎性能。清晰度和可维护性也非常重要。而且,在这种不影响性能的情况下,这是唯一重要的事情。

对于哪种方法更可取,存在着相互竞争的思想流派。

一种观点是其他人提到的:第二种方法减少了嵌套级别,从而提高了代码清晰度。这在命令式风格中是很自然的:当你无事可做时,你不妨早点回来。

另一种观点,从更函数式风格的角度来看,一个方法应该只有一个退出点。函数式语言中的一切都是一种表达。因此 if 语句必须始终有 else 子句。否则 if 表达式并不总是有值。所以在功能风格上,第一种做法更为自然。

Performance-wise, there will be no noticeable difference between the two approaches.

But coding is about more than performance. Clarity and maintainability are also very important. And, in cases like this where it doesn't affect performance, it is the only thing that matters.

There are competing schools of thought as to which approach is preferable.

One view is the one others have mentioned: the second approach reduces the nesting level, which improves code clarity. This is natural in an imperative style: when you have nothing left to do, you might as well return early.

Another view, from the perspective of a more functional style, is that a method should have only one exit point. Everything in a functional language is an expression. So if statements must always have an else clauses. Otherwise the if expression wouldn't always have a value. So in the functional style, the first approach is more natural.

埖埖迣鎅 2024-12-27 05:00:34

这里提出了几个很好的观点,但是如果方法非常冗长,多个返回点也可能不可读。话虽这么说,如果您要使用多个返回点,只需确保您的方法很短,否则可能会失去多个返回点的可读性优势。

There are several good points made here, but multiple return points can be unreadable as well, if the method is very lengthy. That being said, if you're going to use multiple return points just make sure that your method is short, otherwise the readability bonus of multiple return points may be lost.

天涯离梦残月幽梦 2024-12-27 05:00:34

性能分为两部分。当软件投入生产时,您可以获得性能,但您也希望在开发和调试时也具有性能。开发人员最不想做的就是“等待”一些琐碎的事情。最后,在启用优化的情况下编译它将会产生类似的代码。因此,了解这些在这两种情况下都能发挥作用的小技巧是很有好处的。

问题中的情况很清楚,ReSharper 是正确的。您无需嵌套 if 语句并在代码中创建新范围,而是在方法的开头设置明确的规则。它提高了可读性,更容易维护,并且减少了人们必须筛选才能找到他们想要去的地方的规则数量。

Performance is in two parts. You have performance when the software is in production, but you also want to have performance while developing and debugging. The last thing a developer wants is to "wait" for something trivial. In the end, compiling this with optimization enabled will result in similar code. So it's good to know these little tricks that pay off in both scenarios.

The case in the question is clear, ReSharper is correct. Rather than nesting if statements, and creating new scope in code, you're setting a clear rule at the start of your method. It increases readability, it will be easier to maintain, and it reduces the amount of rules one has to sift through to find where they want to go.

久光 2024-12-27 05:00:34

我个人更喜欢只有 1 个出口点。如果您的方法简洁明了,那么这很容易完成,并且它为下一个处理您的代码的人提供了可预测的模式。

例如。

 bool PerformDefaultOperation()
 {
      bool succeeded = false;

      DataStructure defaultParameters;
      if ((defaultParameters = this.GetApplicationDefaults()) != null)
      {
           succeeded = this.DoSomething(defaultParameters);
      }

      return succeeded;
 }

如果您只想在函数退出之前检查函数中某些局部变量的值,这也非常有用。您需要做的就是在最终返回上放置一个断点,并且保证能够命中它(除非抛出异常)。

Personally I prefer only 1 exit point. It's easy to accomplish if you keep your methods short and to the point, and it provides a predictable pattern for the next person who works on your code.

eg.

 bool PerformDefaultOperation()
 {
      bool succeeded = false;

      DataStructure defaultParameters;
      if ((defaultParameters = this.GetApplicationDefaults()) != null)
      {
           succeeded = this.DoSomething(defaultParameters);
      }

      return succeeded;
 }

This is also very useful if you just want to check the values of certain local variables within a function before it exits. All you need to do is place a breakpoint on the final return and you are guaranteed to hit it (unless an exception is thrown).

落墨 2024-12-27 05:00:34

关于代码的外观有很多很好的理由。。但是结果呢?

让我们看一下一些 C# 代码及其 IL 编译形式:

using System;

public class Test {
    public static void Main(string[] args) {
        if (args.Length == 0) return;
        if ((args.Length+2)/3 == 5) return;
        Console.WriteLine("hey!!!");
    }
}

这个简单的代码片段是可以编译的。您可以使用ildasm打开生成的.exe文件并检查结果是什么。我不会发布所有汇编程序的内容,但我会描述结果。

生成的 IL 代码执行以下操作:

  1. 如果第一个条件为 false,则跳转到第二个条件所在的代码。
  2. 如果为 true 则跳转到最后一条指令。 (注:最后一条指令是返回)。
  3. 在第二种情况下,计算结果后也会发生同样的情况。比较并:如果 false,则到达 Console.WriteLine;如果 true,则到达末尾。
  4. 打印消息并返回。

所以看起来代码会跳到最后。如果我们用嵌套代码执行普通的 if 会怎样?

using System;

public class Test {
    public static void Main(string[] args) {
        if (args.Length != 0 && (args.Length+2)/3 != 5) 
        {
            Console.WriteLine("hey!!!");
        }
    }
}

IL 指令的结果非常相似。不同之处在于,之前每个条件有两次跳转:如果 false 则转到下一段代码,如果 true 则转到末尾。现在 IL 代码的流动性更好,并且有 3 次跳转(编译器对此进行了一些优化):

  1. 第一次跳转:当 Length 为 0 时,代码再次跳转(第三次跳转)到末尾。
  2. 第二:在第二个条件的中间避免一条指令。
  3. 第三:如果第二个条件为false,则跳转到末尾。

不管怎样,程序计数器总会跳动。

Many good reasons about how the code looks like. But what about results?

Let's take a look to some C# code and its IL compiled form:

using System;

public class Test {
    public static void Main(string[] args) {
        if (args.Length == 0) return;
        if ((args.Length+2)/3 == 5) return;
        Console.WriteLine("hey!!!");
    }
}

This simple snippet can be compiled. You can open the generated .exe file with ildasm and check what is the result. I won't post all the assembler thing but I'll describe the results.

The generated IL code does the following:

  1. If the first condition is false, jumps to the code where the second is.
  2. If it's true jumps to the last instruction. (Note: the last instruction is a return).
  3. In the second condition the same happens after the result is calculated. Compare and: got to the Console.WriteLine if false or to the end if this is true.
  4. Print the message and return.

So it seems that the code will jump to the end. What if we do a normal if with nested code?

using System;

public class Test {
    public static void Main(string[] args) {
        if (args.Length != 0 && (args.Length+2)/3 != 5) 
        {
            Console.WriteLine("hey!!!");
        }
    }
}

The results are quite similar in IL instructions. The difference is that before there were two jumps per condition: if false go to next piece of code, if true go to the end. And now the IL code flows better and has 3 jumps (the compiler optimized this a bit):

  1. First jump: when Length is 0 to a part where the code jumps again (Third jump) to the end.
  2. Second: in the middle of the second condition to avoid one instruction.
  3. Third: if the second condition is false, jump to the end.

Anyway, the program counter will always jump.

浸婚纱 2024-12-27 05:00:34

避免多个退出点可以带来性能提升。我不确定 C#,但在 C++ 中,命名返回值优化(复制消除,ISO C++ '03 12.8/15)取决于是否有一个出口点。这种优化避免了复制构造您的返回值(在您的具体示例中这并不重要)。这可能会在紧密循环中显着提高性能,因为每次调用函数时都会保存构造函数和析构函数。

但对于 99% 的情况,节省额外的构造函数和析构函数调用并不值得牺牲嵌套 if 块引入的可读性(正如其他人指出的那样)。

Avoiding multiple exit points can lead to performance gains. I am not sure about C# but in C++ the Named Return Value Optimization (Copy Elision, ISO C++ '03 12.8/15) depends on having a single exit point. This optimization avoids copy constructing your return value (in your specific example it doesn't matter). This could lead to considerable gains in performance in tight loops, as you are saving a constructor and a destructor each time the function is invoked.

But for 99% of the cases saving the additional constructor and destructor calls is not worth the loss of readability nested if blocks introduce (as others have pointed out).

失退 2024-12-27 05:00:34

理论上,如果反转 if 能够提高分支预测命中率,则可以带来更好的性能。在实践中,我认为很难准确地知道分支预测将如何表现,特别是在编译之后,所以我不会在日常开发中这样做,除非我正在编写汇编代码。

有关分支预测的更多信息此处

In theory, inverting if could lead to better performance if it increases branch prediction hit rate. In practice, I think it is very hard to know exactly how branch prediction will behave, especially after compiling, so I would not do it in my day-to-day development, except if I am writing assembly code.

More on branch prediction here.

优雅的叶子 2024-12-27 05:00:34

这简直是​​有争议的。关于提前返回的问题,并没有“程序员之间的协议”。据我所知,这总是主观的。

可以进行性能论证,因为最好将条件写下来,这样它们通常都是正确的;也可以说它更加清晰。另一方面,它确实创建了嵌套测试。

我认为您不会对这个问题得到确凿的答案。

That is simply controversial. There is no "agreement among programmers" on the question of early return. It's always subjective, as far as I know.

It's possible to make a performance argument, since it's better to have conditions that are written so they are most often true; it can also be argued that it is clearer. It does, on the other hand, create nested tests.

I don't think you will get a conclusive answer to this question.

×眷恋的温暖 2024-12-27 05:00:34

那里已经有很多有洞察力的答案,但是,我仍然想指出一种稍微不同的情况:实际上,应该将其放在函数之上,而不是先决条件,考虑逐步初始化,您可以在其中进行逐步初始化。必须检查每一步是否成功,然后继续下一步。在这种情况下,您无法检查顶部的所有内容。

当我使用 Steinberg 的 ASIOSDK 编写 ASIO 主机应用程序时,我发现我的代码确实不可读,因为我遵循嵌套范例。它有八层深,我看不到那里的设计缺陷,正如安德鲁·布洛克上面提到的。当然,我可以将一些内部代码打包到另一个函数中,然后将剩余的级别嵌套在那里以使其更具可读性,但这对我来说似乎相当随机。

通过用保护子句替换嵌套,我什至发现了我对清理代码部分的误解,该部分应该在函数中更早出现而不是在最后出现。如果有嵌套的分支,我永远不会看到这一点,你甚至可以说它们导致了我的误解。

因此,这可能是另一种情况,反转 if 有助于使代码更清晰。

There are a lot of insightful answers there already, but still, I would to direct to a slightly different situation: Instead of precondition, that should be put on top of a function indeed, think of a step-by-step initialization, where you have to check for each step to succeed and then continue with the next. In this case, you cannot check everything at the top.

I found my code really unreadable when writing an ASIO host application with Steinberg's ASIOSDK, as I followed the nesting paradigm. It went like eight levels deep, and I cannot see a design flaw there, as mentioned by Andrew Bullock above. Of course, I could have packed some inner code to another function, and then nested the remaining levels there to make it more readable, but this seems rather random to me.

By replacing nesting with guard clauses, I even discovered a misconception of mine regarding a portion of cleanup-code that should have occurred much earlier within the function instead of at the end. With nested branches, I would never have seen that, you could even say they led to my misconception.

So this might be another situation where inverted ifs can contribute to a clearer code.

若沐 2024-12-27 05:00:34

这是一个意见问题。

我的正常方法是避免单行 if,并在方法中间返回。

您不会希望在您的方法中到处出现像它建议的那样的行,但是有一些话要说,用于检查方法顶部的一堆假设,并且只有在它们全部通过时才执行实际工作。

It's a matter of opinion.

My normal approach would be to avoid single line ifs, and returns in the middle of a method.

You wouldn't want lines like it suggests everywhere in your method but there is something to be said for checking a bunch of assumptions at the top of your method, and only doing your actual work if they all pass.

愁以何悠 2024-12-27 05:00:34

在我看来,如果您只是返回 void (或一些您永远不会检查的无用返回代码),那么提前返回就可以了,并且它可能会提高可读性,因为您避免了嵌套,同时您明确表明您的函数已完成。

如果您实际上返回一个 returnValue - 嵌套通常是一种更好的方法,因为您只在一个地方返回 returnValue (最后 - 呃),并且它可能会使您的代码在很多情况下更易于维护。

In my opinion early return is fine if you are just returning void (or some useless return code you're never gonna check) and it might improve readability because you avoid nesting and at the same time you make explicit that your function is done.

If you are actually returning a returnValue - nesting is usually a better way to go cause you return your returnValue just in one place (at the end - duh), and it might make your code more maintainable in a whole lot of cases.

东风软 2024-12-27 05:00:34

我不确定,但我认为 R# 试图避免远跳。当你有 IF-ELSE 时,编译器会执行如下操作:

Condition false ->远跳转到 false_condition_label

true_condition_label:
说明1
...
instructions_n

false_condition_label:
说明1
...
instructions_n

end block

如果条件为 true,则不会跳转,也不会推出 L1 高速缓存,但跳转到 false_condition_label 可能会很远,并且处理器必须推出自己的高速缓存。同步缓存的成本很高。 R# 尝试将远跳转替换为短跳转,在这种情况下,所有指令都已在缓存中的可能性更大。

I'm not sure, but I think, that R# tries to avoid far jumps. When You have IF-ELSE, compiler does something like this:

Condition false -> far jump to false_condition_label

true_condition_label:
instruction1
...
instruction_n

false_condition_label:
instruction1
...
instruction_n

end block

If condition is true there is no jump and no rollout L1 cache, but jump to false_condition_label can be very far and processor must rollout his own cache. Synchronising cache is expensive. R# tries replace far jumps into short jumps and in this case there is bigger probability, that all instructions are already in cache.

风尘浪孓 2024-12-27 05:00:34

我认为这取决于你的喜好,正如前面提到的,没有普遍的共识。
为了减少烦恼,您可以将这种警告减少为“提示”

I think it depends on what you prefer, as mentioned, theres no general agreement afaik.
To reduce annoyment, you may reduce this kind of warning to "Hint"

十级心震 2024-12-27 05:00:34

我的想法是“在函数中间”的返回不应该那么“主观”。
原因很简单,看这段代码:

    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;
    }

也许第一个“返回”不是那么直观,但这确实很节省。
关于干净代码有太多的“想法”,只需要更多的练习就可以摆脱“主观”的坏想法。

My idea is that the return "in the middle of a function" shouldn't be so "subjective".
The reason is quite simple, take this code:

    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;
    }

Maybe the first "return" it's not SO intuitive, but that's really saving.
There are too many "ideas" about clean codes, that simply need more practise to lose their "subjective" bad ideas.

煞人兵器 2024-12-27 05:00:34

这种编码有几个优点,但对我来说最大的好处是,如果你能快速返回,你就可以提高应用程序的速度。 IE 我知道,由于前提条件 X,我可以快速返回错误。这首先消除了错误情况并降低了代码的复杂性。在很多情况下,因为 cpu 管道现在可以更干净,所以可以阻止管道崩溃或切换。其次,如果你处于循环中,快速中断或返回可以节省大量CPU。一些程序员使用循环不变量来执行这种快速退出,但是这样您可能会破坏 cpu 管道,甚至会产生内存查找问题,这意味着 cpu 需要从外部缓存加载。但基本上我认为你应该做你想做的事情,即结束循环或函数而不是创建复杂的代码路径只是为了实现正确代码的一些抽象概念。如果你唯一的工具是锤子,那么一切看起来都像钉子。

There are several advantages to this sort of coding but for me the big win is, if you can return quick you can improve the speed of your application. IE I know that because of Precondition X that I can return quickly with an error. This gets rid of the error cases first and reduces the complexity of your code. In a lot of cases because the cpu pipeline can be now be cleaner it can stop pipeline crashes or switches. Secondly if you are in a loop, breaking or returning out quickly can save you a lots of cpu. Some programmers use loop invariants to do this sort of quick exit but in this you can broke your cpu pipeline and even create memory seek problem and mean the the cpu needs to load from outside cache. But basically I think you should do what you intended, that is end the loop or function not create a complex code path just to implement some abstract notion of correct code. If the only tool you have is a hammer then everything looks like a nail.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文