假设我有这样的代码。
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
之间改变变量,请帮助我。
答案 0 :(得分:4)
执行此操作的一种更简单的方法是使用宏:
macro_rules! f {
($x:ident, $y:ident, $z:ident) => {{
$x += $y;
$y *= $z;
$z %= $x;
}}
}
可以使用f!(x, y, z)
调用此方法。然而,它并不比写一个带有三个&mut int
参数的函数好多了。
现在在特定的情况下,因为x
,y
和z
在范围内,只要您在它们之后编写宏,就可以使用{{ 1}},x
和y
无需通过宏调用传递它们(回想一下Rust是卫生的宏)。也就是说,你可以写
z
以下是完整的代码:
macro_rules! f {
() => {{
x += y;
y *= z;
z %= x;
}}
}
答案 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);
}