我有一个抽象特征,对计算有一些困难的要求,然后对这些计算的结果有一些函数。我想让这个特性保持简单,以便于理解和测试。
trait Calculator {
def hardToCalculate1: Int
def hardToCalculate2: Int
def hardToCalculate3: Int
def result1 = hardToCalculate1 + hardToCalculate2
def result2 = hardToCalculate2 + hardToCalculate3
def result3 = hardToCalculate1 + hardToCalculate3
}
当我实例化一个计算器
时,我将使用Futures来计算这些hardToCalculate
值。假设它们看起来像这样:
def f1 = future {
println("calculating 1")
1
}
def f2 = future {
println("calculating 2")
2
}
def f3 = future {
println("calculating 3")
3
}
所以,我可以像这样构造一个 Future[Calculator]
:
val myCalc = for {
m1 <- f1
m2 <- f2
m3 <- f3
} yield new Calculator {
lazy val hardToCalculate1 = m1
lazy val hardToCalculate2 = m2
lazy val hardToCalculate3 = m3
}
然后,我可能会像这样使用 myCalc
:
myCalc onComplete {
case Success(calc) => println("Result: " + calc.result1)
}
但是当我这样做时,我得到了这个:
calculating 1
calculating 2
calculating 3
Result: 3
我只想在我正在进行的计算确实需要这些 future 时才执行它们。尽管我使用 lazy val
声明了 hardToCalculate
,但所有三个都是在执行 Future[Calculator].onComplete
时计算的。
实现此目的的一种方法是这样的:
val calculator = new Calculator {
lazy val hardToCalculate1 = Await.result(f1, 10 seconds)
lazy val hardToCalculate2 = Await.result(f2, 10 seconds)
lazy val hardToCalculate3 = Await.result(f3, 10 seconds)
}
println("result: " + calculator.result1)
这会产生我想要的结果:
calculating 1
calculating 2
result: 3
但现在我所有的 Await
都被阻塞了。我真正想要的是一个以惰性方式执行 future 的 Future[Calculator]
。如果不将 Futures 引入我的 Calculator
特征中,这可能吗?关于如何获得我想要的东西还有其他建议吗?
最佳答案
如果您创建一个 Future
(使用 scala.concurrent.future
),无论您做什么,它都会被计算。所以你需要一个完全不同的策略。
此外,您的界面甚至不允许远程确定您将实际使用哪些数据。 myCalc
的计算如何知道在 onComplete
中您将只使用 result1
?
你可以:
仅使用惰性值:
val calculator = new Calculator { lazy val hardToCalculate1 = { println("calculating 1") 1 } // ... }
优点:简单
缺点:非异步封装
Future
以允许请求计算:class ReqFuture[T](body: () => T) { lazy val fut = future { body() } }
但是现在您仍然遇到
myCalc
将请求并等待所有这些的问题。因此,您必须在Calculator
中引入ReqFutures
:trait Calculator { def hardToCalculate1: ReqFuture[Int] // ... def result1 = for { h1 <- hardToCalculate1.fut h2 <- hardToCalculate2.fut } yield h1 + h2 }
优点:当您调用
result1
时,只会计算您需要的内容(但仍然只计算一次)。
缺点:result1
现在是一个Future[Int]
。因此,future
已经完全渗透到您的计算器
中。
如果您无法影响Calculator
(我怀疑)并且无法更改result1,2,3
的代码,那么不幸的是,据我所知,您无能为力使执行变得惰性和异步。
关于scala - 用 Future 满足抽象特征要求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17664359/