如何重构对局部可变变量的重复操作?

时间:2014-07-02 07:15:38

标签: rust

假设我有这样的代码。

fn main() {
    let mut x = 123;
    let mut y = 456;
    let mut z = 789;

    x += y; y *= z; z %= x; // random operations
    x = 1;
    x += y; y *= z; z %= x;
    z = z & y;
    x += y; y *= z; z %= x;
    println!("{} {} {}", x, y, z);
}

非常人为,但希望这个想法很清楚 - 我有这些局部变量,我不止一次以某种复杂的方式操纵。

显然,我想避免重复并重构那种操纵。与此同时,涉及的变量太多,我不希望将所有变量作为可变引用参数传递给外部效用函数。

如果这是,比方说,C ++,我可能会将变量存储在全局范围内并定义另一个函数,或者在更新版本中,使用捕获lambda。我尝试在Rust中使用闭包执行相应的操作:

fn main() {
    let mut x = 123;
    let mut y = 456;
    let mut z = 789;

    let f = || {
        x += y; y *= z; z %= x; // random operations
    };

    f();
    x = 1;
    f();
    z = z & y;
    f();
    println!("{} {} {}", x, y, z);
}

但是这并没有编译,因为Rust告诉我,我向x, y, z借了f。似乎f的存在意味着我不能再在x, y, z中使用main了。如果我试图将f传递出函数或者使用它生成一个进程,那么这个Rust错误是有意义的,但我不是,如果我&#它显然是安全的34;手动内联"与第一个版本中的功能相同。

有一种简洁的Rust方法吗?

顺便说一句,我找到了this question,我发现我可以通过在该语句之前终止的块内声明println!来避免上一个f中的错误,但是没有如果我想在调用f之间改变变量,请帮助我。

2 个答案:

答案 0 :(得分:4)

执行此操作的一种更简单的方法是使用宏:

macro_rules! f {
    ($x:ident, $y:ident, $z:ident) => {{
        $x += $y;
        $y *= $z;
        $z %= $x;
    }}
}

可以使用f!(x, y, z)调用此方法。然而,它并不比写一个带有三个&mut int参数的函数好多了。

现在在特定的情况下,因为xyz在范围内,只要您在它们之后编写宏,就可以使用{{ 1}},xy无需通过宏调用传递它们(回想一下Rust是卫生的宏)。也就是说,你可以写

z

以下是完整的代码:

macro_rules! f {
    () => {{
        x += y;
        y *= z;
        z %= x;
    }}
}

在围栏:http://is.gd/sCaYMS

答案 1 :(得分:4)

一种解决方案是使用Cell。无论Cell的可变性如何,Cell的内容都是可变的。这将使代码变得更加丑陋,但至少它会编译。据我所知,表现不应受到影响。

use std::cell::Cell;

fn main() {
    let x = Cell::new(123i);
    let y = Cell::new(456i);
    let z = Cell::new(789i);

    let f = || {
        x.set(x.get() + y.get());
        y.set(y.get() * z.get());
        z.set(z.get() % x.get());
    };

    f();
    x.set(1);
    f();
    z.set(z.get() & x.get());
    f();
    println!("{} {} {}", x, y, z);
}

可能更好的解决方案是将数据和在其上运行的函数抽象为struct。

#[deriving(Show)]
struct Data {
    x: int,
    y: int,
    z: int
}

impl Data {
    fn f(&mut self) {
        self.x += self.y; 
        self.y *= self.z;
        self.z %= self.x;
    }
}


fn main() {
    let mut data = Data { x: 123, y: 456, z: 789 };

    data.f();
    data.x = 1;
    data.f();
    data.z = data.z & data.x;
    data.f();
    println!("{}", data);
}