首页 > 解决方案 > 如何让 Rust 函数传播状态?

问题描述

我需要编写一个 Rust 函数,该函数可以修改在更高函数中定义的状态,并将其从一个函数调用传播到迭代器中的另一个函数调用(参见下面的伪代码)。

在糟糕的 C 语言中,我会使用共享指针来完成。当然,我理解为什么我不应该这样做,以及为什么我不能在 Rust 中这样做。

我发现的解决方法是添加一个额外的函数参数和一个额外的返回参数:

fn f(inputs ..., s) {
    let mut s = s;
    // computations that rely on the value of s
    // ...
    outputs ..., s
}

fn main() {
    let mut s;
    for ... {
        let (outputs ..., x) = f(inputs ..., s);
        s = x;
    }
}

就编程风格而言,这似乎有点沉重,我希望有一个更轻的结构(也许更单子),我想使用闭包。我应该如何写它对我来说并不明显。

标签: rust

解决方案


答案在于参考资料。

C 中的共享指针附带了关于何时何地可以这样做以及何时不能这样做的警告。Rust 有一个借用检查器来确保你没有用指针做任何愚蠢/不安全的事情,以防止人们在 C 中遇到的大部分问题。

例如,考虑您的代码的细微变化(纯粹是为了编译)。可以重写如下:

fn do_with(s: &mut u8, item: u8) {
    *s = *s + item;
}
fn main() {
    let mut s: u8 = 0;
    (1..10).for_each(|item| do_with(&mut s, item));
    println!("{}", s)
}

您会从 C 中识别出这种语法,但它比 C 安全得多,因为借用检查器可确保您的代码在任何给定时间都只有一个可变引用。因此,代码在每一步都被认为是正常的并可以编译。

你也可以像以前那样做,通过有效地从调用到调用的价值。但是,这确实会导致代码的可读性降低和间接级别增加。下面的例子:

fn do_with(s: u8, item: u8) -> u8 {
    s + item
}
fn main() {
    let mut s: u8 = 0;
    (1..10).for_each(|item| s = do_with(s, item));
    println!("{}", s)
}

在 C 中,指针的危险主要在于对它们的维护和维护。由于 Rust 会为您检查并强制执行此操作(并且这 - 积极地 - 可以防止您在使用 时对自己开枪futures),因此这在很大程度上不是问题。


推荐阅读