for 关键字像现代面向对象语言中的 goto 一样已经过时了吗?

发布于 2024-09-11 08:56:48 字数 2850 浏览 3 评论 0原文

for 关键字是否已过时,或者可能会像 C# 或 Java 等语言中的 goto 一样过时?几年后,看到使用 for 的面向对象代码会不会感到奇怪和可疑,就像今天看到 goto 一样非常可疑?

换句话说,有什么理由在程序中了解和使用 for 吗?


我注意到 for 有很多使用 foreach 时不存在的弱点:

“For”很少使用,我们也很少需要它:

不知道关于科学发展,但对于一般性的事情、软件产品和不专门处理微积分的​​网站,for 很少使用。我见过并完成过许多项目,其中数千行代码中没有 for 循环。甚至在处理微积分时,操作数组集合矩阵范围也是更频繁、更优雅的事情比循环有用。

有几个地方看起来需要 for,但实际上并非如此,可以使用面向集合的解决方案来代替。

在阅读初学者开发人员的源代码时,我还发现 for 用于执行 .NET Framework 已经执行的操作。例如,要使用相同的值填充数组,重复N次,有些人会使用循环,而他们必须使用Enumerable.Repeat()

有时,我看到循环用于遍历数组、集合或可枚举。 foreach 将是一个更优雅的解决方案,并且编写起来更短。

“For”不是 Jimmy-proof

可能我是非常糟糕的开发人员,但很多时候,当我使用 for 时,我一次又一次地犯同样的错误:在循环范围中放置除预定义变量之外的其他内容,如下所示:

int SomeValue
{
    get
    {
        // Resources-expensive operation goes here.
    }
}

for (int i = 0; i < this.SomeValue; i++)
{
    // Code here.
}

// Instead, a less stupid developer would write:
int someValue = this.SomeValue;
for (int i = 0; i < someValue; i++)
{
    // ...
}

当然,有什么问题也就是说,每次迭代都会调用 this.SomeValue ,浪费资源。例如,今天晚上,我发现自己犯了一个可怕的错误:循环使用了 0..N 范围,其中 N 是对数据库进行查询的属性。在 SQL Profiler 中看到同一个查询重复了 10000 次,这确实令人惊讶。

“For”很难看:

也许它太主观了,但是当一直操作集合时,第二个解决方案不是更自然的写入/读取吗?

// Solution 1. C style.
for (int i = 0; i < 10; i++)
{
    // Do something.
}

// Solution 2. Enumerable-oriented.
foreach (var i in Enumerable.Range(0, 10))
{
    // Do something.
}

顺便说一句,我觉得第二个更容易理解。之间的区别是:

for (i = 0; i < 10; i++)
for (i = 0; i <= 10; i++)
for (i = 1; i < 10; i++)
for (i = 1; i <= 10; i++)

容易看到吗?而 Enumerable.Range() 只接受两个非常明确的参数:第一个 - 从哪里开始,以及元素的数量。

更复杂的代码怎么样?

foreach (string containingTwo in Enumerable.Range(0, 10).
    Where(c => c.ToString().Contains('2')).
    Select(c => c.ToString().PadLeft(8)))
{
    Console.Write(containingTwo);
}

“For”过于僵化:

很难扩展for。假设我们想要在网站上显示页面列表而不使用 ASP.NET 分页控件。最明显的解决方案是使用 for (int i = 1; i <= countPages; i++) 显示数字。

现在,如果需求发生变化并且我们不想显示每个页面,而只想显示前两页、最后两页、当前页面和距离当前最近的页面怎么办?

如果我们使用集合,那么更改就会很容易。实际上,对于循环来说,事实并非如此。

“For”对 Linq 不友好:

Linq 可以做很多事情,避免手工编写。但是当我们使用for时,Linq就没有位置了。如果需要进行过滤,我们必须自己进行。如果必须转换结果,则必须在单独的行上完成。是的,当然,lambda 表达式也可以在简单的循环中使用,但是没有一种易于阅读的方法可以将所有内容编写在一行简短的代码中。 SumAverage 不可用,就像 JoinExceptGroupBy 一样。

Is for keyword obsolete or may become obsolete just as goto in languages like C# or Java? In a few years, will it be strange and suspicious to see an object-oriented code which uses for, like today, it's very suspicious to see gotos?

In other words, is there any reason to know and use for in programs?


I notice that there are a bunch of weaknesses with for that doesn't exist when using foreach:

'For' is rarely used and we rarely need it:

Don't know about scientific development, but to do general stuff, software products and websites not dealing especially with calculus, for is used extremely rarely. I've seen and done many projects where there were no for loop in thousands of lines of code. Probably even when dealing with calculus, manipulating arrays, collections or matrices or ranges is something much more frequent, elegant and useful than a loop.

A few places when it seems that for is required, in fact, it is not, and a collection-oriented solution may be used instead.

Reading source code of beginner developers, I also find for used to do what .NET Framework already does. For example, to fill an array with the same value, repeated N times, some people will use a loop, when they must rather use Enumerable.Repeat().

Sometimes, I see that a loop is used to walk through an array, a collection or an enumerable. foreach would be a much more elegant solution, and shorter to write.

'For' is not Jimmy-proof:

Probably I'm a very bad developer, but very often, when I use for, I make the same mistake again and again: putting something other than a predefined variable in the loop range, like this:

int SomeValue
{
    get
    {
        // Resources-expensive operation goes here.
    }
}

for (int i = 0; i < this.SomeValue; i++)
{
    // Code here.
}

// Instead, a less stupid developer would write:
int someValue = this.SomeValue;
for (int i = 0; i < someValue; i++)
{
    // ...
}

Of course, what's wrong with that is that this.SomeValue is called at each iteration, wasting resources. For example, this evening, I found a terrible mistake I've done: a loop used a 0..N range where N was a property making a query to a database. It was really surprising to see in the SQL Profiler than the same query was repeated 10 000 times.

'For' is ugly:

Maybe it's too subjective, but when manipulating collections all the time, what isn't a second solution more natural to write/read?

// Solution 1. C style.
for (int i = 0; i < 10; i++)
{
    // Do something.
}

// Solution 2. Enumerable-oriented.
foreach (var i in Enumerable.Range(0, 10))
{
    // Do something.
}

By the way, I find the second one easier to understand. Is a difference between:

for (i = 0; i < 10; i++)
for (i = 0; i <= 10; i++)
for (i = 1; i < 10; i++)
for (i = 1; i <= 10; i++)

easy to see? Whereas Enumerable.Range() accepts only two parameters, which are extremely clear: the first one - where to start, and the number of elements.

What about more elaborate code?

foreach (string containingTwo in Enumerable.Range(0, 10).
    Where(c => c.ToString().Contains('2')).
    Select(c => c.ToString().PadLeft(8)))
{
    Console.Write(containingTwo);
}

'For' is too rigid:

It's difficult to extend for. Let's say we want to display a list of pages on a website without using ASP.NET paging control. The most obvious solution would be to display numbers with a for (int i = 1; i <= countPages; i++).

Now, what if the requirements change and we don't want to display every page, but only the first two, the last two, the current and the nearest pages to the current?

If we were using a collection, it would be easy to change. Actually, with a loop, it is not.

'For' is not Linq friendly:

There are plenty of things Linq can do, avoiding writing it by hand. But when we use for, there is no place for Linq. If there is a filtering to do, we must do it ourselves. If the results must be converted, this must be done on a separate line. Yes, of course, lambda expressions can be used inside a simple loop too, but there is no an easy-to-read way to write all the stuff in a single, short line of code. Sum or Average are just not available, just as Join or Except or GroupBy.

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

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

发布评论

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

评论(5

苯莒 2024-09-18 08:56:48

在我当前的 C# 项目中,有一个地方仍然使用传统的 for 循环,并且处理左右移动数组以找到两条曲线之间的最佳匹配。在这种情况下,foreach 在语义上根本不足以让陌生人弄清楚发生了什么。这看起来是正确的:

for(int shift = -5; shift <= 5; shift++)
    // shift data and compare

是的,从技术上讲,我可以在 Range(-5,5) 上使用 foreach ,但在我看来,这似乎是完成同样事情的肮脏黑客。我不是根据数字进行操作,而是它们是我操作的一个组成部分。我觉得 foreach 应该位于您希望检索/更新/yield 的域对象上。

有时我也会处理非常大的(数百万/数十亿个元素)double[]。对 forforeach 运行秒表,我发现 foreachfor 慢大约 1.5 倍> 在处理此类数组时。我怀疑,当 .NET 5.0 出现时,性能将非常相似,因为所有内容都将被视为某种形式的 IEnumerable。基本上已经存在了,至少在精神上是这样。

但在大多数情况下我同意。我认为最终,我们将看到传统 for 循环的用途逐渐取代 foreach 样式循环。不过,我希望随后将其缩短为 for,因为这样打字速度更快。我一直不明白为什么他们不走 Java 路线,而只是在 for 中允许两个不同的表达式。

In my current C# project, there is one place that still uses a traditional for loop, and that deals with shifting an array left and right to find the best match between two curves. In this case, foreach is simply not semantically proper enough for a stranger to figure out what is going on. This just looks right:

for(int shift = -5; shift <= 5; shift++)
    // shift data and compare

Yes, I could technically use a foreach over a Range(-5,5), but that seems to me like a dirty hack for accomplishing the same thing. I'm not operating on the numbers, but rather they are a component of my operation. I feel a foreach should be over the domain objects you wish to retrieve/update/yield.

I also sometimes deal with very large (millions/billions of elements) double[]s. Running a stopwatch over both a for and foreach, I find that the foreach is about 1.5x slower than the for in processing such arrays. I suspect that by the time .NET 5.0 hits, the performance will be quite similar as everything will be treated as some form of IEnumerable. It's basically there already, at least in spirit.

But for the most part I agree. I think eventually, we will see the purpose of the traditional for loop fade in preference for a foreach style loop. However, I hope that this will subsequently be shortened back into for, because it's simply quicker to type. I never understood why they didn't go the Java route on that and simply allow two different expressions inside for.

热鲨 2024-09-18 08:56:48

在 Java(和其他一些语言)中,您仍然使用 for 关键字进行“foreach”循环:

for (String s : myListOfString) { 
    // code code code
}

因此您可能需要重新表述这个问题,但如果您的意思是“您认为我们会停止使用 for (int i=0; i... 循环 (for i in range(len(myList))) 不鼓励迭代集合(请参阅 delnan 的评论 - 说得好),或多或少是出于您在中提到的原因你原来的问题。

In Java (and some other languages), you still use the for keyword for a "for each" loop:

for (String s : myListOfString) { 
    // code code code
}

So you might want to rephrase the question, but if you mean "do you think we'll stop using for (int i=0; i<something; i++) loops, then you might definitely be right. In Python, the equivalent of for (int i=0;... loops (for i in range(len(myList))) is discouraged for iterating over a collection (see delnan's comment -- well put), more or less for the reasons you mentioned in your original question.

陌生 2024-09-18 08:56:48

尽管有些人可能不喜欢,但我仍然经常看到它,并且这是一种非常紧凑且(在我看来)可读的生成循环的方式。我知道在 Java 中,每个人都使用 for 循环,事实上我很少看到 foreach 结构。也就是说,总会有人继续使用 for 循环,也有人会讨厌这些人。

关于你的另一个问题,你绝对有必要知道如何执行 for 循环(相信我,这并不难),就像你需要知道如何执行 > while 循环。 foreach 能够有效地完成一些事情,因此您偶尔会使用 for。至于你是否使用它,那是你的选择。

Although some might dislike for, I still see it all the time, and it's a very compact and (in my opinion) readable way to generate loops. I know in Java, everyone uses for loops, in fact I rarely see a foreach construction. That said, there will always be people who will continue to use for loops and people who will hate those people.

On your other question, it is definitely necessary for you to know how to do a for loop (and believe me, it isn't hard), just like you need to know how to do a while loop. There are some things that foreach will be able to do effectively, so you'll occasionally use for. As to whether you use it, that's your choice.

中二柚 2024-09-18 08:56:48

我对 for 循环遇到的最大问题是当它们嵌套时,我不小心写了一个 i 而不是 j 或反之亦然......尤其是在 for 标头内,例如在增量或条件部分期间。幸运的是,我已经训练自己在这种情况下要格外小心:D

虽然不是面向对象,但我认为 for 循环在函数式编程中(大部分)已经过时了。

The biggest issue I have with for loops is when they are nested and I accidentally write an i instead of a j or vice-versa... especially inside the for header, such as during the increment or condition part. Luckily I have trained myself to be extra careful in such situations :D

Although not OO, I think for loops are (mostly) obsolete in functional programming.

半窗疏影 2024-09-18 08:56:48

我是错的还是应该

for (int i = 0; i = someValue; i++)

for (int i = 0; i <= someValue; i++)

也不是 for 循环,通常比 foreach 循环更好优化
或者 C# jit 是否可以优化

foreach (var i in Enumerable.Range(0, 10))
{
    // Do something.
}

的标准参数的字节码

for (int i = 0; i < 10; i++)
{
    // Do something.
}

为相当于在此处插入有关优化与清晰度

如果由我决定,我们都会使用 Smalltalk 风格的 for 循环,即在每个集合上调用匿名函数,但这可能会产生严重的后果放缓潜力。

Am I wrong or should

for (int i = 0; i = someValue; i++)

be

for (int i = 0; i <= someValue; i++)

Also aren't for loops usually better optimized then foreach loops
or can the c# jit optimize

foreach (var i in Enumerable.Range(0, 10))
{
    // Do something.
}

into the bytecode equivalent of

for (int i = 0; i < 10; i++)
{
    // Do something.
}

insert standard argument about optimization vs clarity here

If it was up to me we would all be using smalltalk style for loops, ie calling a anonymous function on each of a collection but that might have serious slowdown potential.

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