Stateless Future支持发生器1。发生器功能类似Scala的for/yield推导式,但发生器比for/yield推导式更灵活。你可以用Stateless Future生成很复杂的惰性求值容器。

用法

首先,想好你的容器中的元素类型,创建一个Generator

import com.qifun.statelessFuture.util.Generator
val gen = Generator[Int] // 创建用来生成Seq[Int]的发生器

然后创建gen.Future

val genFuture = gen.Future {
  for (i <- gen.futureSeq(0 until 3)) {
    gen(i * i).await // 生成容器中的一项,值是i*i
  }
}

gen.Future是一种特殊的Future,专门用于发生器。gen.Futurecom.qifun.statelessFuture.Future的类型有微妙的区别,相互之间不能隐式转换。gen.futureSeq则类似上一节中介绍的futureSeq,可以配合gen.Future使用。

最后把genFuture转换成gen.OutputSeq

val genSeq: gen.OutputSeq = genFuture

gen.OutputSeq派生于SeqgenSeq是个惰性求值的容器,内容是Seq(0, 1, 4, 9)

等价的for/yield推导式

这种惰性求值容器也可以用普通的for/yield推导式生成:

val forYieldSeq: Seq[Int] =
  for (i <- (0 until 10).view) yield { // view后缀使得for语句返回支持惰性求值的SeqView,而不是普通的Seq
    i * i
  }

forYieldSeq也是个惰性求值的容器,内容也是Seq(0, 1, 4, 9)

进阶用法

虽然上例中的for/yield也能涵盖发生器最简单的用法,但是除此之外,发生器中还可以容纳任意控制语句,这种进阶用法就没办法靠for/yield实现了。

import com.qifun.statelessFuture.util.Generator
val gen = Generator[Int]
val genSeq2: gen.OutputSeq = gen.Future {
  gen(-1).await
  for (i <- gen.futureSeq(0 until 3)) {
    gen(i * i).await
    if (i == 2) {
      gen(i).await
      gen(i).await
      gen(i).await
    }
  }
  gen(-2, -3, -2).await // 在一行代码中生成多个元素
}

genSeq2的值是Seq(-1, 0, 1, 4, 2, 2, 2, 9, -2, -3, -2),这样灵活的控制流程,比for/yield功能强。

(待续)


  1. 发生器
    即Generator,是用来控制循环迭代行为的一种特殊子例程。例如C#的yield功能就是发生器。参见维基百科


杨博

岂凡 游戏架构师