yield是生成器中的特有用法,而生成器是一种可以封闭整个运行状态、可以随时暂停继续的模型,从传统的程序观点是很难描述它的,但是似乎跟函数式编程有比较密切的关系(虽然我并没有学过函数式编程……)设想我们有一个函数,它返回一个序列,这个序列可以是无限长的(也可以是有限长)。当然,无限长的序列我们是表示不出来的,内存会爆。但是我们通常可以把它表示成一个广义表,它的第一项是下一个值,而第二项是剩下所有值用同样方法形成的广义表,也就是说我们把返回值:改写成如果原始的序列是有限长的,则最终某个子表里只有一个元素。这样的形式对传统的程序来说似乎没什么用,但是一般我们认为广义表是可以延迟求值的,也就是说我们可以每次取一个值,然后需要的时候再去计算下一个子表。这个模型就对应到了生成器。我们每次调用生成器让它返回下一个值的时候,就相当于取出子表中第一项的同时,将生成器推进到了下一个子表中,这样我们得生成器就可以返回任意有限甚至无限多个元素,而且只在需要的时候才计算出它们。接下来我们知道,返回一个子表,和返回一个“返回子表的函数”,其实没有什么区别。那么如果返回的这个函数还能接受参数呢?我们可以在获取上一个值之后,给这个生成器传入一个新的值,从而影响之后返回的结果,这个就是yield表达式的作用了,它返回一个值,这个值实际上是从外部传入的,也就是我们看到的输入的参数。但是生成器其实又跟真正的函数式编程不同,它是在传统编程方法当中实现一个这样功能结构的语法,真正的函数式编程自然会毫不犹豫地将它写成尾递归的形式。但我们也知道,尾递归可以转化成循环,那么生成器通常就是将尾递归转化成循环之后的形式,它的内部封闭了所有本来应该在递归中作为参数传递的状态,这样我们可以用传统的编程的方法来写这个生成器,这样在许多时候是比较方便的,比如说问题异常复杂,比如说需要调用I/O等非幂等的方法的时候。由于生成器的第二种形式可以看成每次都隐含返回一个接受参数的函数,这个函数可以代替异步编程中的回调函数,从而用生成器编写异步过程,这种方法许多时候也被叫做协程,但从一开始就强调生成器的这种用法我觉得是不科学的,它其实只是用生成器代替了异步回调函数而已,并不是自己就具有独立执行的能力,把生成器叫做协程容易让初学者忽略了调度器在异步程序中的重要作用,造成误导。垍
标签:YIOS