【问题标题】:Implementing computational graph in Rust在 Rust 中实现计算图
【发布时间】: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


【解决方案1】:

这是可能的。基本上,this works:

let input = Input::<i64>::new();

let s1 = input.fork();
s1.subscribe(|x| {
    println!("s1: {}", x)
});

let s2 = input.fork();
s2.map(|x| x * 3).subscribe(|x| {
    println!("s2: {}", x)
});

let s3 = input.fork().map(|x| {
    let s3 = (x as f64) + 100.5;
    println!("s3: {}", s3);
    s3
}).share();

s3.fork().map(|x| x + 1.).subscribe(|x| println!("s4: {}", x));

s3.fork().map(|x| x + 2.).subscribe(|x| println!("s5: {}", x));

input.feed(1);
println!("---");
input.feed(2);

和输出

s1: 1
s2: 3
s3: 101.5
s4: 102.5
s5: 103.5
---
s1: 2
s2: 6
s3: 102.5
s4: 103.5
s5: 104.5

实现方面:Rc&lt;RefCell&lt;Vec&lt;Box&lt;Trait&gt;&gt;&gt;&gt; 和许多生命周期标记...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-11
    • 1970-01-01
    • 2020-08-22
    • 1970-01-01
    • 2023-04-06
    • 2017-02-06
    • 2021-03-31
    • 1970-01-01
    相关资源
    最近更新 更多