设为首页 加入收藏

TOP

深圳scala-meetup-20180902(2)- Future vs?Task?and?ReaderMonad依赖注入(一)
2019-08-15 00:11:31 】 浏览:154
Tags:深圳 scala-meetup-20180902 Future Task and ReaderMonad 依赖 注入

  在对上一次3月份的scala-meetup里我曾分享了关于Future在函数组合中的问题及如何用Monix.Task来替代。具体分析可以查阅这篇博文。在上篇示范里我们使用了Future来实现某种non-blocking数据库操作,现在可以用Task替换Future部分:

  class KVStore[K,V] { private val kvs = new ConcurrentHashMap[K,V]() def create(k: K, v: V): Task[Unit] = Task.delay(kvs.putIfAbsent(k,v)) def read(k: K): Task[Option[V]] = Task.delay(Option(kvs.get(k))) def update(k: K, v: V): Task[Unit] = Task.delay(kvs.put(k,v)) def delete(k: K): Task[Boolean] = Task.delay(kvs.remove(k) != null) }

Task是一个真正的Monad,我们可以放心的用来实现函数组合:

  type FoodName = String type Quantity = Int type FoodStore = KVStore[String,Int] def addFood(food: FoodName, qty: Quantity)(implicit fs: FoodStore): Task[Quantity] = for { current <- fs.read(food) newQty = current.map(cq => cq + qty).getOrElse(qty) _ <- fs.update(food,newQty) } yield newQty def takeFood(food: FoodName, qty: Quantity)(implicit fs: FoodStore): Task[Quantity] = for { current <- fs.read(food) cq = current.getOrElse(0) taken = Math.min(cq,qty) left = cq - taken _ <- if(left > 0) fs.update(food,left) else fs.delete(food) } yield taken def cookSauce(qty: Quantity)(get: (FoodName,Quantity) => Task[Quantity], put: (FoodName,Quantity) => Task[Quantity]): Task[Quantity] = for { tomato <- get("Tomato",qty) vaggies <- get("Veggies",qty) _ <- get("Galic",10) sauceQ = tomato/2 + vaggies * 3 / 2 _ <- put("Sauce",sauceQ) } yield sauceQ def cookPasta(qty: Quantity)(get: (FoodName,Quantity) => Task[Quantity], put: (FoodName,Quantity) => Task[Quantity]): Task[Quantity] = for { pasta <- get("Pasta", qty) sauce <- get("Sauce", qty) _ <- get("Spice", 3) portions = Math.min(pasta, sauce) _ <- put("Meal", portions) } yield portions

跟上次我们使用Future时的方式没有两样。值得研究的是如何获取Task运算结果,及如何更精确的控制Task运算如取消运行中的Task:

  implicit val refridge = new FoodStore val shopping: Task[Unit] = for { _ <- addFood("Tomato",10) _ <- addFood("Veggies",15) _ <- addFood("Garlic", 42) _ <- addFood("Spice", 100) _ <- addFood("Pasta", 6) } yield() val cooking: Task[Quantity] = for { _ <- shopping sauce <- cookSauce(10)(takeFood(_,_),addFood(_,_)) meals <- cookPasta(10)(takeFood(_,_),addFood(_,_)) } yield meals import scala.util._ import monix.execution.Scheduler.Implicits.global val cancellableCooking = Cooking.runOnComplete { result => result match { case Success(meals) => println(s"we have $meals pasta meals for the day.") case Failure(err) => println(s"cooking trouble: ${err.getMessage}") } } global.scheduleOnce(1 second) { println(s"its taking too long, cancelling cooking ...") cancellableCooking.cancel() }

在上面例子里的addFood,takeFood函数中都有个fs:FoodStore参数。这样做可以使函数更加通用,可以对用不同方式实施的FoodStore进行操作。这里FoodStore就是函数的依赖,我们是通过函数参数来传递这个依赖的。重新组织一下代码使这种关系更明显:

  class Refridge { def addFood(food: FoodName, qty: Quantity): FoodStore => Task[Quantity] = { foodStore =>
      for { current <- foodStore.read(food) newQty = current.map(c => c + qty).getOrElse(qty) _ <- foodStore.update(food, newQty) } yield newQty } def takeFood(food: FoodName, qty: Quantity): FoodStore => Task[Quantity] = { foodStore =>
      for { current <- foodStore.read(food) cq = current.getOrElse(0) taken = Ma
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇深圳scala-meetup-20180902(1)-.. 下一篇安装 Scala

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目