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. Java web--反射(解刨)

    本质:先加载类           再解刨类的方法,字段,构造函数 目的:解刨出构造函数       为了new对象 解刨出字段             为了封装数据进去 解刨方法           ...

  2. rediscluster 集群操作(摘抄)

    一:关于redis cluster 1:redis cluster的现状 目前redis支持的cluster特性 1):节点自动发现 2):slave->master 选举,集群容错 3):Ho ...

  3. COleChangeSourceDialog不能Change Source的解决方法

      在微软给的例子OClient中,有选中一个OLE对象然后Change Source的功能,但是会报错.分析了一下是这样的: void CMainView::OnOleChangeSource() ...

  4. SQL 基础:Select语句,各种join,union用法

    一.基本的SELECT语句 1. “*”的注意事项:在SELECT语句中,用*来选取所有的列,这是一个应该抵制的习惯. 虽然节省了输入列名的时间,但是也意味着获得的数据比真正需要的数据多的多.相应的, ...

  5. C# 队列集合的使用

    using System; using System.Collections.Generic; using System.Text; using System.Collections; namespa ...

  6. 循序渐进Python3(六) -- 初识内置变量、反射、递归

    #python用下划线作为变量前缀和后缀指定特殊变量.稍后我们会发现,   #对于程序来说,其中的有些变量是非常有用的,而其他的则是未知或者无用的.   #我们总结一下Python中下划线的特殊用法  ...

  7. JQuery this 和 $(this) 详解

    this  this 在面向对象语言中,指代调用上下文对象,在js中,也是一模一样的概念,所以不管这个this出现在什么地方,只要追踪到当前调用对象是什么,那么this是什么也就一目了然了. 先看一个 ...

  8. JSP(forward动作)登录功能

    <%@ page language= "java" contentType="text/html;charset=UTF-8" %><html ...

  9. WordPress主机

  10. AngularJS学习---更多模板(More Templating) step 8

    1.切换分支 amosli@amosli-pc:~/develop/angular-phonecat$ git checkout step- #切换分支 amosli@amosli-pc:~/deve ...