以下是版本0.3.1 中使用scala.rx的基本hello world示例。
由于缺少implicit ownerCtx: rx.Ctx.Owner
,它无法编译。我如何获得此实例?
import rx._
val a = Var(1)
val b = Var(2)
val c = Rx{ a() + b() }
This Rx might leak! Either explicitly mark it unsafe (Rx.unsafe) or ensure an implicit RxCtx is in scope!
[error] val c = Rx{ a() + b() }
[error] ^
[error] one error found
有趣的是,在scala REPL中它有效!?
scala> import rx._
val a = Var(1)
val b = Var(2)
val c = Rx{ a() + b() }
import rx._
scala> a: rx.Var[Int] = Var@2c(1)
scala> b: rx.Var[Int] = Var@2f(2)
scala> c: rx.Rx.Dynamic[Int] = Rx@d1(3)
scala>
更新
添加implicit val ctx = Ctx.Owner.Unsafe
代码后编译。但这看起来不安全......
答案 0 :(得分:0)
只有当请求rx.Ctx.Owner
的代码位于仅运行一次的代码块内时,似乎提供rx.Ctx.Owner
的隐式值才会自动宏<魔术。其中包括object
s,val
s,lazy val
s等
此示例将编译时没有问题,因为val c = ...
将只评估一次。
object Once {
val a = Var(1)
val b = Var(2)
//no need to provide `implicit ownerCtx: rx.Ctx.Owner`
val c = Rx {
a() + b() -> Rx {a() - b()}
}
}
同样提到的示例,但在scala REPL中粘贴。
此限制是由于 scala.rx 库中的 Rx泄漏问题。它们在创建更高阶Rx变量(包含另一个Rx变量的Rx变量)时存在。有关泄漏问题的更多信息,请参阅sala.rx project site。
作为泄漏的补救措施 - 引入了rx.Ctx.Owner
的概念和voodo-macro。 scala.rx的这个例外显示了有趣的部分。请注意Owner
个随播广告对象和implicit def voodoo: Owner
:
object Owner extends Generic[Owner]{
object Unsafe extends Owner(???){
implicit val Unsafe: Ctx.Owner.Unsafe.type = this
}
/**
* Dark magic. End result is the implicit ctx will be one of
* 1) The enclosing RxCtx, if it exists
* 2) RxCtx.Unsafe, if in a "static context"
* 3) RxCtx.CompileTime, if in a "dynamic context" (other macros will rewrite CompileTime away)
*/
@compileTimeOnly("@}}>---: A rose by any other name.")
implicit def voodoo: Owner = macro Factories.automaticOwnerContext[rx.Ctx.Owner]
}
事实证明,静态代码块只评估一次并且不受泄漏的影响。这就是voodoo
允许编译器查找隐式的原因。尝试以这种方式设计代码。
如果代码不是静态代码并且您确定代码只会评估一次(例如测试中的脚本),则常见的解决方案是从Unsafe
伴侣提供Owner
隐式实例宾语。只需导入import Ctx.Owner.Unsafe._
然后。
这里是如何在BasicTests scala.rx来源中完成的:
package rx
import util.{Failure, Success}
import utest._
import acyclic.file
object BasicTests extends TestSuite{
//We dont care about potential Rx leaks in BasicTest
import Ctx.Owner.Unsafe._
...