似乎仅当请求的代码位于仅运行一次的代码块内时,才提供隐式值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 项目站点上阅读有关泄漏问题的更多信息。
作为泄漏的补救措施 -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._
吧。
这里是如何在scala.rx源的 BasicTests 中完成的:
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._
...