2016-01-13 83 views

回答

5

AFAICT似乎F#对待VALUETYPE以类似的方式枚举为C#:

下面是一个简单的C#程序的IL代码的分解段,它使用的foreach一个多IEnumerable<T>

.locals init (
    [0] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>, 
    [1] int32 v 
) 
IL_0025: ldloca.s 0 
IL_0027: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext() 

注意local 0是一个值类型,它使用ldloca.s加载结构的地址。

与F#

.locals init (
    [0] class [mscorlib]System.Collections.Generic.List`1<int32> ra, 
    [1] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> 
) 
IL_000e: ldloca.s 1 
IL_0010: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext() 

此代码还使用值类型声明local 1ldloca.s加载结构的地址进行比较。

附注:后来的F#版本确实做了C#不能做的优化。因为它是F#中的一种常见模式,可以遍历不可变数据结构的F#列表,所以使用枚举数进行迭代是无效的。所以F#有一个列表的特例,并且在这种情况下应用更高效的算法。在C#中迭代F#列表将回退到枚举器。

也可以实现IList类型的特殊处理,但由于可能有人以“有趣”的方式实现了IList,所以这是实现这种优化的潜在突破变化。