D中的for和foreach语句
除了句法上的差异,这两种语言本质上是一样的吗?它们都是用核心语言实现的吗?或者D中的for和foreach语句,d,D,除了句法上的差异,这两种语言本质上是一样的吗?它们都是用核心语言实现的吗?或者foreach是标准库的一部分?就性能而言,如果我选择一个而不是另一个,是否会产生差异?foreach和foreach之间的主要区别在于 foreach-循环的抽象。一个foreach-循环通常会降低到某些级别 用于编译器循环。这至少有四个优点: 可读性:foreach(a;someArray)doSomething(a)本质上是更多的 对于(size_t i=0;i
foreach
是标准库的一部分?就性能而言,如果我选择一个而不是另一个,是否会产生差异?foreach和foreach之间的主要区别在于
foreach
-循环的抽象。一个foreach
-循环通常会降低到某些级别
用于编译器循环。这至少有四个优点:
可读性:foreach(a;someArray)doSomething(a)代码>本质上是更多的
对于(size_t i=0;i代码>。
如果someArray
的类型不是一个简单的数组,这一点就更清楚了
灵活性:如果在某个时间点,您决定
someArray
必须从某个数组更改为范围或对象
(例如,为了实现并行循环),foreach
保持不变,而
for
-必须将循环更改为使用empty
、front
和popFront
(对于范围)或opApply
或其他机制(对于范围)
类或结构
特殊功能,例如,对类型元组进行迭代,解码UTF-8和
UTF-16字符串
性能:foreach
循环让编译器决定如何优化
基于类型实现循环(迭代数组、范围、,
字符串、对象…)以及可能的其他信息(例如
类型)。这允许对所有类型和其他编译器进行有效的实现
优化,而不必太担心实现
细节。实际上,foreach
相对于手工编码的for
情况好坏参半foreach(dcharc;someString){…}
(即UTF-8的解码
循环时的字符串)非常快。但是foreach(a;someObject){…}
,其中
someObject
实现了opApply
,速度稍慢(因为循环体是
包装到委托中,opApply通常在循环中调用此委托,这
产生一些开销)。和往常一样,在99.99%的应用程序中,这对您的代码来说并不重要
这些情况,如foreach总是会产生(至少)体面的实现
主要的缺点(除此之外,有时还有速度)是有些东西不能
用foreach完成,即循环的事物的许多突变
(例如,调整循环体中数组的大小)。如果可能,应始终使用
foreach
foreach
迭代几乎所有内容(甚至元数据,如编译时数据类型)<代码>用于不能
foreach (Type; TypeTuple!(int, long, short)) { pragma(msg, Type); }
但是,使用for
循环无法做到这一点foreach
可用于在编译时执行操作(上面的扩展);例如,如果您有一段重复10次的代码,您可以说:
template Iota(size_t a, size_t b) //All integers in the range [a, b)
{
static if (a < b) { alias TypeTuple!(a, Iota!(a + 1, b)) Iota; }
else { alias TypeTuple!() Iota; }
}
foreach (i; Iota!(0, 10)) { int[i] arr; } //Not possible with 'for'
如果n
大于2^32-1,则为危险,但
foreach (i; 0 .. n) { arr[i]++; }
不是,因为编译器会自动为迭代选择正确的类型。这也提高了可读性您知道对于不在范围内的数组,如何降低foreach的
?如何显式访问数组迭代器?很抱歉,请您发表评论。我想,这与这篇作品有关。嗯,我开始阅读阿里·切雷利的书中关于范围的章节,他指出,通过减少切片长度可以在数组上进行迭代,我注意到,切片一个固定大小的数组会使它变成一个与范围兼容的迭代器。使用array[0..$]
是在固定大小的数组上获得与范围兼容的“迭代器”的最简单方法(但请注意不要从中删除元素,这将导致GC分配的副本中断切片和数组之间的元素共享)。
foreach (i; 0 .. n) { arr[i]++; }