【发布时间】:2018-10-24 00:01:05
【问题描述】:
我正在尝试在 Rust 中实现类似 ReactiveX(例如,有点类似于 RxJava/RxJS 和朋友)的图形引擎,但仅面向同步计算,重点是中间值缓存。它有点像标准库迭代器,但倒退了。
我必须实现 Observable/Observer 模式的玩具原型:Playground——尽管它最终不是我想要的,但它展示了事物的一般精神。
基本上,我想要看起来像这样的代码(伪代码):
let mut input = Input();
let mut x = input.map(|i| i * 2);
// unavoidable multiple mut borrow?..
let mut y = x.fork().map(|x| x + 3) // [must_use]
y.subscribe(|y| println!("y={}", y)); // moved
let mut z = x.fork().map(|x| x - 4).do_more_stuff(); // [must_use]
z.subscribe(|z| println!("z={}", z)); // moved
// some time later:
input.feed(42);
大致展开成这样
|i| {
let x = i * 2;
let y = x + 3;
println!("y={}", y);
let z = do_more_stuff(x - 4);
println!("z={}", z);
}
语法在这里很重要,我知道如何“向后”执行或显着修改它以便它可以工作,但为了便于阅读,如果可能的话,我想保留“自上而下”的语法,'尤其是叉子。
因此您可以将其视为有向图,顶部有一个输入,每个节点进行一些计算并将结果(可能多次;或者可能不传递)传递到底层,可能“分叉”,以便可以将值传递给多个较低级别的节点而无需重新计算。在最底层,有“订阅者/观察者”,他们可以倾听价值观并用它们做任何事情。一旦创建,这个图(即图结构)是完全不可变的。
在许多 Rx 框架的实现中,可以在不显式地将值作为结构字段携带的情况下执行此操作,因为它将存在于父闭包中。
我在 Rust 中花费了大量时间思考和原型设计,但似乎无法找到一个快速且“不错”的好解决方案,即符合人体工程学,如上面的示例所示。例如,使用fork()(拆分流),所需的语法类型立即暗示对父级的多个可变借用,即使子级后来被移动?
我认为可行的核心思想(在上面链接的操场中实现)是:观察者概念 - 基本上,要求实现者实现on_next(&mut self, value: T) 的特征,因此任何FnMut(T) -> () 都可以自动实现它.然后,“fork”是包含Box<Observer> 列表的东西,以便它可以调用它们。也许是一个“流/可观察”,它可以接受一个订阅它的观察者(以可变的方式?)。
无论如何,也许我在这里撞到了一堵众所周知的墙,或者也许有更好的解决方案(或者也许这已经在某个地方实施)——任何想法都会非常感激。
【问题讨论】:
-
如果
fork()消费自己并返回两个独立的对象,是否可以接受? -
@orlp 是的,当然。
-
@orlp 我认为设法解决了它......虽然有点痛苦:)(见答案)
标签: rust