为什么我应该在循环中使用foreach而不是for(inti=0;I<length;I++)?
在C#和Java中,似乎最酷的循环方式是使用foreach而不是C风格进行循环
有什么理由让我更喜欢这种风格而不是C风格吗
我对这两个案例特别感兴趣,但请尽可能多地解释你的观点
- 我希望对列表中的每个项目执行操作李>
- 我正在搜索列表中的某个项目,并希望在找到该项目后退出李>
你可以在下面搜索框中键入要查询的问题!
在C#和Java中,似乎最酷的循环方式是使用foreach而不是C风格进行循环
有什么理由让我更喜欢这种风格而不是C风格吗
我对这两个案例特别感兴趣,但请尽可能多地解释你的观点
# 1 楼答案
对我来说,一个好处是不太容易犯像这样的错误
更新: 这是错误发生的一种方式。我算了一笔钱
然后决定将其聚合更多。所以我用另一个循环来包装这个循环
当然,编译失败,所以我们手工编辑
现在代码中至少有两个错误(如果我们搞乱了maxi和maxj,还会有更多错误),这些错误只会被运行时错误检测到。如果你不写测试。。。这是一段罕见的代码,它会严重地伤害其他人
这就是为什么将内部循环提取到方法中是一个好主意:
而且更具可读性
# 2 楼答案
foreach
更简单,可读性更强对于链表这样的结构,它可能更有效
并非所有集合都支持随机访问;迭代
HashSet<T>
或Dictionary<TKey, TValue>.KeysCollection
的唯一方法是foreach
foreach
允许您在不使用额外临时变量的情况下迭代方法返回的集合:# 3 楼答案
我能想到的两个主要原因是:
1)它从底层容器类型中抽象出来。例如,这意味着您不必在更改容器时更改循环容器中所有项的代码——您指定的是“为容器中的每个项执行此操作”的目标,而不是的意思
2)它消除了一次关闭错误的可能性
就对列表中的每个项目执行操作而言,直观地说:
它完美地向读者表达了意图,而不是手动使用迭代器。搜索项目同上
# 4 楼答案
想象一下,你是一家餐厅的主厨,你正在为自助餐准备一份巨大的煎蛋。你把一盒一打的鸡蛋递给两个厨房工作人员,然后让他们开始吃鸡蛋
第一种方法是设置一个碗,打开板条箱,依次从左到右抓住每一个鸡蛋——从上一排到下一排——将鸡蛋靠着碗的侧面打碎,然后将鸡蛋倒进碗中。最后,他的鸡蛋用完了。做得好的工作
第二个人摆好碗,打开板条箱,然后冲出去拿一张纸和一支笔。他把数字0到11写在鸡蛋盒的隔间旁边,把数字0写在纸上。他看了看纸上的数字,找到标有0的隔间,取出鸡蛋并将其放入碗中。他又看了看纸上的0,想“0+1=1”,划掉0,把1写在纸上。他从1舱抓起鸡蛋,把它打碎。以此类推,直到数字12出现在纸上,他才知道(没有看!)没有鸡蛋了。做得好的工作
你会认为第二个人的脑袋有点乱,对吧
使用高级语言的目的是避免用计算机的术语来描述事物,并且能够用自己的术语来描述它们。语言的层次越高,这一点就越真实。增加循环中的计数器会分散您真正想做的事情:处理每个元素
除此之外,通过增加计数器和索引,无法有效地处理链表类型的结构:“索引”意味着从头开始计数。在C语言中,我们可以通过使用循环“计数器”的指针并取消引用来处理我们自己创建的链表。我们可以在现代C++中(使用C语言)和java语言来使用这一点,但是这仍然存在间接性问题。p>
最后,有些语言已经达到了相当高的水平,以至于写一个循环来“对列表中的每个项目执行操作”或“搜索列表中的项目”的想法是令人震惊的(就像厨师长不必告诉第一个厨房工作人员如何确保所有鸡蛋都破裂一样)。提供了设置循环结构的函数,您可以通过一个高阶函数,或者在搜索情况下通过一个比较值,告诉它们在循环中要做什么。(事实上,C++中可以做这些事情,尽管接口有些笨拙。)
# 5 楼答案
foreach
将在所有场景中执行与for
相同的操作[1],包括您描述的简单场景但是
foreach
与for
相比,具有某些与性能无关的优势:i
(这在生活中除了促进循环之外没有其他用途),您也不需要自己将当前值提取到变量中;循环构造已经解决了这个问题李>foreach
,您可以同样轻松地迭代不是数组的序列。如果您想使用for
在非数组顺序的序列(例如映射/字典)上循环,那么您必须以稍微不同的方式编写代码foreach
在它涵盖的所有情况下都是相同的李>因此,正如我们所看到的,
foreach
在大多数情况下使用“更好”这就是说,如果您出于其他目的需要
i
的值,或者如果您正在处理一个您知道是数组的数据结构(并且它是数组有一个实际的特定原因),那么更深入的金属for
提供的增加的功能将是一条出路[1]“在所有场景中”实际上是指“集合易于迭代的所有场景”,这实际上是“大多数场景”(见下面的注释)。然而,我真的认为涉及不友好的迭代集合的迭代场景必须被设计
# 6 楼答案
通过对列表中的每个项目执行操作您的意思是在列表中适当地修改它,还是简单地对项目执行一些操作(例如打印、累积、修改等)?我怀疑是后者,因为C#中的
foreach
不允许您修改正在循环的集合,或者至少不允许以方便的方式修改集合下面是两个简单的构造,首先使用
for
,然后使用foreach
,它们访问列表中的所有字符串并将它们转换为大写字符串:(请注意,在.NET中使用结束条件
i < list.Count
而不是带有某个预计算机length
常量的i < length
被认为是一种很好的做法,因为编译器无论如何都必须在list[i]
时检查上界。)在循环中调用;如果我的理解是正确的,编译器在某些情况下能够优化掉上限检查(通常会这样做)以下是
foreach
等价物:注意:基本上,
foreach
构造可以在C#中的任何IEnumerable
或IEnumerable<T>
上迭代,而不仅仅是在数组或列表上。因此,集合中的元素数量可能事先未知,甚至可能是无限的(在这种情况下,您肯定必须在循环中包含一些终止条件,否则它将不会退出)下面是我能想到的几个等价的解决方案,使用C#LINQ表示(它引入了lambda表达式的概念,基本上是一个内联函数,在下面的示例中使用
x
并返回x.ToUpper ()
):或者使用由其构造函数填充的
uppercase
列表:或者使用
ToList
函数执行相同操作:或者仍然与类型推断相同:
或者,如果您不介意将结果作为
IEnumerable<string>
(字符串的可枚举集合),您可以删除ToList
:或者是另一个带有类似C#SQL的
from
和select
关键字的,完全等效的:LINQ非常有表现力,我觉得代码比普通循环更具可读性
您的第二个问题,在列表中搜索一个项目,并希望在找到该项目时退出,也可以使用LINQ非常方便地实现。下面是一个
foreach
循环的示例:以下是简单的LINQ等价物:
或使用查询语法:
results
枚举只在按需时执行,这意味着实际上,当调用列表上的FirstOrDefault
方法时,该列表将只迭代到满足条件为止我希望这能为{}或{}辩论带来更多的背景,至少在未来几年。网络世界