Ruby 2.0有一个新的特性是惰性枚举器,Soi Mort 的博客举了一个例子:可以将下面的代码

File.open(path) {|fp|
fp.each_line. \
select {|line| # 生成了临时数组
/regexp/ =~ line
}. \
each_with_index.map {|line, no| # 生成了临时数组
sprintf("%d: %s\n", no, line)
}. \
first(10).each {|str| # 生成了临时数组
puts(str)
}
}

转换为

File.open(path) {|fp|
fp.each_line.lazy \
select {|line| # 没有临时数组产生
/regexp/ =~ line
}. \
each_with_index.map {|line, no| # 没有临时数组产生
sprintf("%d: %s\n", no, line)
}. \
first(10).each {|str| # 没有临时数组产生
puts(str)
}
} # 甚至在到达EOF之前都不读取数据

这样来避免产生多余的临时对象。这里谈到了惰性枚举,其实这个概念并不算太新鲜,在.NET引以为傲的Linq中,惰性枚举其实越来越重要。

初学C#的时候其实并不容易搞清楚所谓的IEnumerable和IEnumerator,有个时候就糊弄一下觉得大多数情况很少手工操作迭代器和枚举器,用一个foreach就巧妙的解决并自鸣得意。但是看了《CLR via C#》以及一些关于C#的案例和图书似乎都很少出现foreach,有时候还纳闷特么这些人是蠢的么...当然,后来发现foreach的实现方式导致其本身效率是不高的所以...。

回头看.NET的IEnumerable接口:

public interface IEnumerable
{
//
// Methods
//
[DispId (-4)]
IEnumerator GetEnumerator ();
}

这个接口只需要实现一个GetEnumerator的方法,非常简洁。

IEnumerator接口:

public interface IEnumerator
{
//
// Properties
//
object Current {
get;
} //
// Methods
//
bool MoveNext (); void Reset ();
}

于是我们便可以实现一个仅能duang出来一个的“列表”:

class OnlyOne : IEnumerable, IEnumerator
{
public IEnumerator GetEnumerator () => this;
public object Current => "caocaoda";
public bool MoveNext () => false;
public void Reset () {}
}

如果把false改为true那就可以一直艹艹哒啦。

但是这样的话,还是很麻烦,毕竟要我们手工实现,说好的C#简单呢...所以M$引入了一个迭代器,用以实现IEnumerable/IEnumerator。

class OnlyOne : IEnumerable
{
public IEnumerator GetEnumerator()
{
Int32 value = 0;
do {
yield return value++;
} while (false);
}
}

省事太多,通过DILASM可以看到其实编译器帮我们实现了前面我们自己写的方法。

通过IL不难看出,其实MoveNext()是一个Switch...

废话那么多回到惰性枚举上来,其实我们发现,IEnumerable和IEnumerator两个接口的实现其实是惰性的,也就是在需要的时候才会获取数据,而不会产生临时的数据,就像前面Ruby一样,使用迭代器不会产生额外的开销。如果我们把false改成了true,还没有“惰性”那玩意儿可够呛...

为什么说Linq其实很依赖惰性枚举呢...举个例子:

public static IEnumerable Take (Int32 much, IEnumerable s)
{
for (int i = 0; i < much; i++) {
yield return s [i];
}
}

我们就可以实现一个在数据源中抓much个元素的方法了。

你在说什么?##

其实我就是打算复习一下迭代器而已...

C#的惰性枚举的更多相关文章

  1. C#函数式程序设计之惰性列表工具——迭代器

    有效地处理数据时当今程序设计语言和框架的一个任务..NET拥有一个精心构建的集合类系统,它利用迭代器的功能实现对数据的顺序访问. 惰性枚举是一个迭代方法,其核心思想是只在需要的时候才去读取数据.这个思 ...

  2. swfupload多文件上传[附源码]

    swfupload多文件上传[附源码] 文件上传这东西说到底有时候很痛,原来的asp.net服务器控件提供了很简单的上传,但是有回传,还没有进度条提示.这次我们演示利用swfupload多文件上传,项 ...

  3. 聊一聊C# 8.0中的await foreach

    AsyncStreamsInCShaper8.0 很开心今天能与大家一起聊聊C# 8.0中的新特性-Async Streams,一般人通常看到这个词表情是这样. 简单说,其实就是C# 8.0中支持aw ...

  4. C# 8中的Async Streams

    关键要点 异步编程技术提供了一种提高程序响应能力的方法. Async/Await模式在C# 5中首次亮相,但只能返回单个标量值. C# 8添加了异步流(Async Streams),允许异步方法返回多 ...

  5. C#8.0中的 await foreach

    AsyncStreamsInCShaper 8.0 C# 8.0中支持异步返回枚举类型async Task<IEnumerable<T>> sync Streams这个功能已经 ...

  6. Python 入门基础11 --函数基础4 迭代器、生成器、枚举类型

    今日目录: 1.迭代器 2.可迭代对象 3.迭代器对象 4.for循环迭代器 5.生成器 6.枚举对象 一.迭代器: 循环反馈的容器(集合类型) 每次重复即一次迭代,并且每次迭代的结果都是下一次迭代的 ...

  7. Stream01 定义、迭代、操作、惰性求值、创建流、并行流、收集器、stream运行机制

    1 Stream Stream 是 Java 8 提供的一系列对可迭代元素处理的优化方案,使用 Stream 可以大大减少代码量,提高代码的可读性并且使代码更易并行. 2 迭代 2.1 需求 随机创建 ...

  8. Effective Java - 构造器私有、枚举和单例

    目录 饿汉式单例 静态常量 静态代码块 懒汉式单例 尝试加锁 同步代码块 双重检查 静态内部类单例 枚举单例 Singleton 是指仅仅被实例化一次的类.Singleton代表了无状态的对象像是方法 ...

  9. Swift enum(枚举)使用范例

    //: Playground - noun: a place where people can play import UIKit var str = "Hello, playground& ...

随机推荐

  1. Hibernate day03笔记

      Hibernate的关联关系映射:(多对多) 多对多的配置: 步骤一创建实体和映射: Student: public class Student {     private Integer sid ...

  2. node,不懂不懂

    Four Day-------------------------node.js分对象全局/核心模块/文件模块path(核心模块)--作用:操作路径basername/获取传入路劲dimame/获取传 ...

  3. mongodb账号安全操作

    安装服务 mongod --install --serviceName mongodb --storageEngine=mmapv1 --dbpath i:\mongodb\data --journa ...

  4. DescriptionResourcePathLocationType Dynamic Web Module 3.0 requires Java

    先保证ide的所有jdk都在1.6及以上,如果还是错就试试下面的 在<build></build>中添加 <plugins> <plugin> < ...

  5. 种类并查集(POJ 1703)

    1703 -- Find them, Catch them http://poj.org/problem?id=1703 题目大意:有2个敌对帮派,输入D a b表示a,b在不同帮派,输入A a b表 ...

  6. C++之jsoncpp学习

    最新由于客户端要用到jsoncpp,所以自己也跟着项目的需求学了一下jsoncpp.以前没用过xml,但是感觉接触json后,还蛮好用的. 参考地址 http://jsoncpp.sourceforg ...

  7. java-web乱码问题解决

    <一>乱码问题(设置tomcat uriencoding=’utf-8’); 统一设置编码过滤器 <1>get请求: request.setCharacterEncoding( ...

  8. POJ 2155 Matrix (二维树状数组)

    Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 17224   Accepted: 6460 Descripti ...

  9. freemarker 数字格式化函数

    ${num?string('0.00')} 如果小数点后不足两位,用 0 代替 ${num?string('#.##')} 如果小数点后多余两位,就只保留两位,否则输出实际值 输出为:1239765. ...

  10. codeforces 420B Online Meeting

    一道实现很蛋疼的题.必须静下理清思路,整理出各种情况.不然就会痛苦地陷入一大堆if..else里不能自拔. #pragma comment(linker, "/STACK:102400000 ...