Rust 借用对结构中属性的引用

Rust 借用对结构中属性的引用,rust,Rust,如果借用对结构字段的引用,则整个结构被视为借用。我已经成功地把我想做的事情孤立出来并举例说明。我只想获得对B中某个字段的“只读”引用,以获取一些数据,然后修改B的另一个字段。有没有一种惯用的生锈方法 struct A { i: i32, } struct B { j: i32, a: Box<A>, } impl B { fn get<'a>(&'a mut self) -> &'a A { &am

如果借用对结构字段的引用,则整个结构被视为借用。我已经成功地把我想做的事情孤立出来并举例说明。我只想获得对
B
中某个字段的“只读”引用,以获取一些数据,然后修改
B
的另一个字段。有没有一种惯用的生锈方法

struct A {
    i: i32,
}

struct B {
    j: i32,
    a: Box<A>,
}

impl B {
    fn get<'a>(&'a mut self) -> &'a A {
        &*self.a
    }
    fn set(&mut self, j: i32) {
        self.j = j
    }
}

fn foo(a: &A) -> i32 {
    a.i + 1
}

fn main() {
    let a = Box::new(A { i: 47 });
    let mut b = B { a: a, j: 1 };
    let a_ref = b.get();
    b.set(foo(a_ref));
}

这是语言的一个特点。从编译器的角度来看,当通过
get()
借用
a
时,它无法知道调用
set()
函数是安全的

您的
get()
函数可变地借用
b
,并返回一个引用,因此
b
将保持借用状态,直到该引用超出范围

您有几种处理方法:

  • 将两个字段分隔为两个不同的结构

  • B方法中移动需要访问这两个属性的代码

  • 将属性公开,这样就可以直接获取对它们的引用

  • 在设置之前计算新值,如下所示:

    fn main() {
        let a = Box::new(A { i: 47 });
        let mut b = B { a: a, j: 1 };
        let newval = {
            let a_ref = b.get();
            foo(a_ref)
        };
        b.set(newval);
    }
    
  • 稍微扩展一下

    B方法中移动需要访问这两个属性的代码

    第一次通过时可能是这样的:

    impl B {
        fn do_thing(&mut self) {
            self.j = self.a.foo()
        }
    }
    
    但是,这会对调用
    foo
    进行硬编码。您也可以接受一个闭包,以使其更灵活:

    impl B {
        fn update_j_with_a<F>(&mut self, f: F)
        where
            F: FnOnce(&mut A) -> i32,
        {
            self.j = f(&mut self.a)
        }
    }
    
    // ...
    
    b.update_j_with_a(|a| a.foo())
    
    可以换成

    struct A {
        description: String,
        info: Info,
    }
    
    struct Info {
        name: String,
        age: u8,
        money: i32,
    }
    
    impl A {
        fn update_description(&mut self) {
            let description = &mut self.description;
            *description = self.info.build_description()
        }
    }
    
    impl Info {
        fn build_description(&self) -> String {
            format!(
                "{} is {} years old and has {} money",
                self.name,
                self.age,
                self.money
            )
        }
    }
    
    fn main() {}
    

    您可以将这两个步骤结合起来(我认为这是更好的做法),然后将该方法移到内部结构上。

    注意,在
    中,在设置新值之前计算新值。
    ,额外的大括号会导致
    b.get
    中的可变引用的作用域在我们尝试
    设置
    值之前过期-这很好地回到了点“
    b
    将保持借用状态,直到该引用超出作用域”。
    struct A {
        description: String,
        info: Info,
    }
    
    struct Info {
        name: String,
        age: u8,
        money: i32,
    }
    
    impl A {
        fn update_description(&mut self) {
            let description = &mut self.description;
            *description = self.info.build_description()
        }
    }
    
    impl Info {
        fn build_description(&self) -> String {
            format!(
                "{} is {} years old and has {} money",
                self.name,
                self.age,
                self.money
            )
        }
    }
    
    fn main() {}