有条件地捕获闭包中的变量实现自定义控件

Conditionally capture variables in closure to implement custom control

我正在尝试用 Rust 实现自定义控制结构。例如,假设出于某种原因,我想将自定义 if 语句实现为一个函数。该函数将接受一个条件,一个代表真分支的闭包和一个代表假分支的闭包。根据情况,我会称其为真分支闭包或假分支闭包。

看起来像这样:

pub fn fun_if<O>(
    cond: bool,
    mut tbranch: impl FnMut() -> O,
    mut fbranch: impl FnMut() -> O,
) -> O {
    if cond {
        tbranch()
    } else {
        fbranch()
    }
}

这个实现的问题是 true 闭包不能可变地借用与 false 闭包相同的变量:

let mut test = 0;
fun_if(true, || test = 1, || test = 2)
                ^^^^         ^^^^ ! error !

不过rust if语句很聪明,知道true和false分支永远不会一起调用。以下编译就好了:

let mut test = 0;
if true {
    test = 1
} else {
    test = 2
}

我的问题是 if 的行为是否可以用 rust 中的函数和不安全代码复制。

(这是一个稍微做作的例子,如果有人感兴趣,我很乐意提供真实的例子。不过我在这里问的是核心思想。)

除了 Stargateurs link,这在一般情况下是绝对正确的,我想指出这个特定问题可以用宏轻松解决。这是我对这个问题的看法。

macro_rules! macro_if {
    ($cond:expr, $t:stmt, $f:stmt) => {
        if ($cond) {
            $t
        } else {
            $f
        }
    };
}

用法示例

let return_val = macro_if!(
        !cond,
        {
            test = 1;
            0
        },
        {
            test = 2;
            5
        }
    );

由于宏是在编译时求值的,因此该解决方案支持您的用例,同时仍然保留 Rust 编译器安全地推理您的代码的能力。虽然在这个简单的示例中使用 unsafe 可能是合理和正确的,但更复杂的情况可能会很快导致您的实现中出现不合理的错误。我们不希望这种情况发生。

这种方法的缺点是它可能会破坏宏调用中的自动完成功能。至少对我来说,宏与 rls 不能很好地协调(还)。