Предположим, я хочу сделать кофе. Это включает 4 шага:
- 1a. молотые кофейные зерна
- 1б. нагреть воду
- 2. объединить
- 3. фильтр
Все эти шаги требуют времени, поэтому они возвращают будущее. Это наш домен:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
import scala.concurrent.{Await, Future}import scala.concurrent.ExecutionContext.Implicits.global //We need an executionContext to run futuresimport scala.concurrent.duration._ //This provides the "1 second" syntaxclass CoffeeBeans()class GroundCoffee()class ColdWater()class WarmWater()class UnfilteredCoffee()class FilteredCoffee()//we start out with beans and cold waterval beans = new CoffeeBeans()val water = new ColdWater()def grindBeans(beans: CoffeeBeans) = Future { new GroundCoffee() }def heatWater(water: ColdWater) = Future { new WarmWater() }def combine(groundCoffee: GroundCoffee, water: WarmWater) = Future { new UnfilteredCoffee() }def filter(unfilteredCoffee: UnfilteredCoffee) = Future { new FilteredCoffee() } |
Один из способов связать фьючерсы — это onSuccess:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
val fGrind: Future[GroundCoffee] = grindBeans(beans)val fHeat: Future[WarmWater] = heatWater(water)val fStep1: Future[(GroundCoffee, WarmWater)] = fGrind.zip(fHeat)fStep1.onSuccess { case (groundCoffee, warmWater) => val fCombine: Future[UnfilteredCoffee] = combine(groundCoffee, warmWater) fCombine.onSuccess { case unfilteredCoffee => val fFilter: Future[FilteredCoffee] = filter(unfilteredCoffee) fFilter.onSuccess { case successCoffee => println(s"$successCoffee is ready!") } }}Thread.sleep(1000)//wait for the coffee to be ready |
Используя flatmap, мы можем упростить это до:
|
01
02
03
04
05
06
07
08
09
10
11
|
val fGrind: Future[GroundCoffee] = grindBeans(beans)val fHeat: Future[WarmWater] = heatWater(water)val fStep1: Future[(GroundCoffee, WarmWater)] = fGrind.zip(fHeat)val fCombine: Future[UnfilteredCoffee] = fStep1.flatMap { case (groundCoffee, warmWater) => combine(groundCoffee, warmWater)}val fFilter: Future[FilteredCoffee] = fCombine.flatMap { case unfilteredCoffee => filter(unfilteredCoffee)}val flatmapCoffee: FilteredCoffee = Await.result(fFilter, 1 second) |
Обратите внимание, что у нас есть будущее нашего фильтрованного кофе на самом высоком уровне. Это мило! Мы можем вернуть его или позвонить в службу Await. Получите его, чтобы дождаться готовности нашего кофе.
Так как для понимания это более короткий способ написания flatMaps, мы можем упростить его до этого:
|
1
2
3
4
5
6
|
val fFor = for { groundCoffee <- grindBeans(beans) warmWater <- heatWater(water) unfilteredCoffee <- combine(groundCoffee, warmWater)} yield filter(unfilteredCoffee)val forCoffee: FilteredCoffee = Await.result(fFilter, 1 second) |
ура!
| Ссылка: | Цепочка фьючерсов на scala от нашего партнера JCG Таммо Сминии в блоге JDriven . |