Предположим, я хочу сделать кофе. Это включает 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 futures import scala.concurrent.duration._ //This provides the "1 second" syntax class CoffeeBeans() class GroundCoffee() class ColdWater() class WarmWater() class UnfilteredCoffee() class FilteredCoffee() //we start out with beans and cold water val 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 . |