Rust 以可变方式借用结构字段并将其传递给可变方法

Rust 以可变方式借用结构字段并将其传递给可变方法,rust,Rust,因为rust不跟踪跨方法调用的单个字段借用-它假定您从整个结构中借用了字段,所以不可能从结构中借用字段,返回它,然后将其传递给其他可变方法。这听起来有点做作,但我现在有一个确切的问题 struct Foo { x: i32, y: i32 } impl Foo { pub fn borrow_x(&mut self) -> &mut i32 { &mut sel

因为rust不跟踪跨方法调用的单个字段借用-它假定您从整个结构中借用了字段,所以不可能从结构中借用字段,返回它,然后将其传递给其他可变方法。这听起来有点做作,但我现在有一个确切的问题

    struct Foo {
        x: i32,
        y: i32
    }
    
    impl Foo {
        pub fn borrow_x(&mut self) -> &mut i32 {
            &mut self.x
        }
    
        pub fn cross_product(&mut self, other: &mut i32) {
            self.y *= *other;
            *other *= self.y;
        }
    }
    
    fn main() {
        let mut foo = Foo{x: 2, y: 4};
        let x_ref = foo.borrow_x();
        foo.cross_product(x_ref);
    
        println!("x={} y={}", foo.x, foo.y);
    }
这当然在rust中是不允许的,编译器的错误是:

error[E0499]: cannot borrow `foo` as mutable more than once at a time
  --> src/main.rs:20:5
   |
19 |     let x_ref = foo.borrow_x();
   |                 --- first mutable borrow occurs here
20 |     foo.cross_product(x_ref);
   |     ^^^               ----- first borrow later used here
   |     |
   |     second mutable borrow occurs here
我的第一反应是使用“不安全”来告诉编译器它并不是真正从self借用的:

    pub fn borrow_x<'a>(&mut self) -> &'a mut i32 {
        unsafe {
            std::mem::transmute::<&mut i32, &'a mut i32>(&mut self.x)
        }
    }
我认为可以将该方法全部抛弃,将对这两个字段的引用作为自由函数传递到cross_乘积中。这应该等同于上一个解决方案。但我发现这种情况很糟糕,尤其是当结构所需的字段数量增加时


这个问题还有其他解决方案吗?

需要记住的是,rust是在每个功能级别工作的

        pub fn cross_product(&mut self, other: &mut i32) {
            self.y *= *other;
            *other *= self.y;
        }
可变性规则确保
self.y
other
不是一回事。 如果不小心的话,很容易在C++/C/Java中遇到这种错误

i、 想象一下,如果

        let x_ref = foo.borrow_x();
        foo.cross_product(x_ref);
你在干什么

        let y_ref = foo.borrow_y();
        foo.cross_product(y_ref);
foo.y
应该以什么值结束?(允许这些引用同一对象可能会导致某些性能优化不适用)

正如你提到的,你可以使用一个自由函数

fn cross_product(a: &mut i32, b: &mut i32) {
  a *= b;
  b *= a;
}
<> P>但我会考虑开沟变异性

fn cross_product(a:i32, b:i32) -> (i32,i32) {
  (a*b, a*b*b)
}
旁白:如果返回值对您来说很奇怪(最初对我也是如此),并且您希望
(a*b,a*b)
,那么您需要更仔细地思考一下。。。我要说的是,这本身就是避免可变版本的一个很好的理由

那我就可以这样用了

let (_x,_y) = cross_product(foo.x, foo.y);
foo.x = _x; 
foo.y = _y;
这有点冗长,但当我们到达时,我们可以改为写:

(foo.y, foo.x) = cross_product(foo.x, foo.y);

需要记住的是,rust在每个功能级别都起作用

        pub fn cross_product(&mut self, other: &mut i32) {
            self.y *= *other;
            *other *= self.y;
        }
可变性规则确保
self.y
other
不是一回事。 如果不小心的话,很容易在C++/C/Java中遇到这种错误

i、 想象一下,如果

        let x_ref = foo.borrow_x();
        foo.cross_product(x_ref);
你在干什么

        let y_ref = foo.borrow_y();
        foo.cross_product(y_ref);
foo.y
应该以什么值结束?(允许这些引用同一对象可能会导致某些性能优化不适用)

正如你提到的,你可以使用一个自由函数

fn cross_product(a: &mut i32, b: &mut i32) {
  a *= b;
  b *= a;
}
<> P>但我会考虑开沟变异性

fn cross_product(a:i32, b:i32) -> (i32,i32) {
  (a*b, a*b*b)
}
旁白:如果返回值对您来说很奇怪(最初对我也是如此),并且您希望
(a*b,a*b)
,那么您需要更仔细地思考一下。。。我要说的是,这本身就是避免可变版本的一个很好的理由

那我就可以这样用了

let (_x,_y) = cross_product(foo.x, foo.y);
foo.x = _x; 
foo.y = _y;
这有点冗长,但当我们到达时,我们可以改为写:

(foo.y, foo.x) = cross_product(foo.x, foo.y);