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