【问题标题】:What's the benefit of range based for loop over traditional c style for loop?基于范围的 for 循环与传统的 c 风格 for 循环相比有什么好处?
【发布时间】:2021-01-21 13:34:27
【问题描述】:

我正在实现我自己的编程语言,并为选择什么 for 循环语法感到困惑。

似乎所有最新最酷的语言都在使用基于范围的 for 循环。为了了解它的优缺点,我用谷歌搜索,唯一的答案似乎是cleaner and cooler。 虽然我可以顺势而为。我无法说服自己它比 c 风格的 for 循环更好。

我认为支持 for(:)、foreach、for ... in... 之类的快捷方式很棒,但不应该支持旧的 c 样式 for 循环作为通用后备吗?

for(int i =0;i<len;++i) {}

因为它非常灵活,可以轻松处理所有可能的情况。对我来说,这是“少即是多”的一个例子。

有了它,我不需要像这样搜索答案:

using range based for loop for iterating on a sub range

Reverse Range in Swift

https://www.dotnetperls.com/range-swift

Skip 1st Iteration of Range-Based For Loops

我只需要记住一种语法就可以实现一切。例如,下面的 sn -p 实现了一个运行长度编码算法。您可以在子 while 循环中更新 for 循环的索引。你不需要不断地进步。您不必预先定义循环行为。

// CPP program to implement run length encoding
#include <bits/stdc++.h>
using namespace std;
 
void printRLE(string str)
{
    int n = str.length();
    for (int i = 0; i < n; i++) {
 
         // Count occurrences of current character
        int count = 1;
        while (i < n - 1 && str[i] == str[i + 1]) {
            count++;
            i++;
        }

        // Print character and its count
        cout << str[i] << count;
    }
}
 
int main()
{
    string str = "wwwwaaadexxxxxxywww";
    printRLE(str);
    return 0;
}

基于范围的循环主要是为了语言人体工程学吗?

但是这些不丑吗?你最终会输入更多内容来达到同样的效果。

for i in stride(from:5,through:1,by:-1) { print(i) } // 5 4 3 2 1

for (n, prime) in primes.enumerated() {}

编辑: 写完第一个问题,我隐隐约约记得swift好像一开始就支持c风格的for循环,后来去掉了。在谷歌上搜索了这段历史之后,我找到了https://github.com/apple/swift-evolution/blob/master/proposals/0007-remove-c-style-for-loops.md,这背后有一些原因。我不认为“不太像 Swift”。虽然很合乎逻辑......

【问题讨论】:

  • stride(from: 5,through: 1,by: -1) 在这种情况下,您实际上不需要使用stride。我会选择for i in (1...5).reversed(),我认为它更好。我认为你遗漏了一些东西:基于范围的循环只是一个特例。一般来说,所有的 Swift 循环只适用于Sequence,任何Sequence。这就是使它们如此出色的原因,循环的序列不仅仅是一种语言结构,它是可以传递的一等公民。您可以mapfilterreduce(1...5).reversed()。你不能对(int i = 5; i &gt; 0; i--) 这样做,因为它不是“东西”

标签: swift programming-languages language-design range-based-loop


【解决方案1】:

对于任何用例,C 风格的循环似乎都足够强大。那么为什么不使用它们呢?

想到的一个原因是安全性:从集合中分离索引会导致大量错误。例如,经典的 array-index-out-of-bounds 错误:也许程序员忘记了你的语言是 0 索引的,或者他们将计数器增加了太多次,或者可能出现了其他问题——我相信大多数程序员有过这样的经历。相反,当你有某种基于范围的语法时,就不可能(以这种方式)搞砸了。

(当然,你总是可以决定避免这些错误是程序员的工作。毕竟,能力越大,责任越大!许多语言已经决定走这条路,或者至少允许走这条路。我知道至少one very successful example。)

关于“丑陋”这一点,我实际上发现 C 风格的循环比许多替代方案更丑陋。一方面,它通常最终成为额外的样板——for i in range(1...5) { … i … }for (i = 0; i &lt; range(1...5).length(); ++i) { … range(1...5)[i] … } 更直接。正如我所提到的,精心设计的计数器操作方案很容易搞砸。作为一个更倾向于功能的人,我会更愿意接受一个更可证明是正确的方案。

说到函数倾向:C 风格的循环可能不适合您的语言范式。在许多语言中,“for 循环”甚至不是一个自然的概念!如果您的主要结构是 s 表达式(如在 Lisp 中),则范围样式循环(又名 map)比 for 循环自然得多。 (如果你想要真正纯粹,改变计数器变量也不自然。)我注意到这往往出现在高度关注结构递归的编程语言中(想想 LISP、Haskell、派雷特等)。结构递归非常棒,因为它的定义非常明确,尤其是与不规则递增的循环相比时。

此时的问题是“但为什么要使用功能范式?”可能会出现……但这已在其他地方广泛讨论过。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-31
    • 2013-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-23
    相关资源
    最近更新 更多