PAYATHON 2026

Rust 如何同时获取多个结构体字段的可变引用?

数据小陈

结论

Rust 允许同时持有指向不同结构体字段的可变引用,也允许同时借用 Vec 中不同元素,前提是这些借用互不重叠。问题中的访问器方法每次都会可变借用整个 MyStruct。因此,调用 x.a() 并保留返回值后,再调用 x.b() 就会发生借用冲突。可以在一次借用中拆分字段,也可以用能证明元素互不重叠的切片操作。

原代码还有两处类型和语法问题:字段 b 的类型是 f32,示例变量却声明为 &mut i32;入口函数应写作 fn main() { ... }。

同时借用不同字段

直接借用不同字段时,Rust 能识别它们彼此独立:

pub struct MyStruct {
    a: i64,
    b: f32,
    c: Vec<bool>,
}

fn main() {
    let mut x = MyStruct {
        a: 34,
        b: 23.023,
        c: vec![true, false, true, false],
    };

    let a: &mut i64 = &mut x.a;
    let b: &mut f32 = &mut x.b;

    *a += 1;
    *b += 1.0;
}

如果要通过方法访问这些字段,可以让一个方法同时借用它们,并在 MyStruct 内部拆分借用:

impl MyStruct {
    pub fn a_b(&mut self) -> (&mut i64, &mut f32) {
        (&mut self.a, &mut self.b)
    }
}

fn main() {
    let mut x = MyStruct {
        a: 34,
        b: 23.023,
        c: vec![true, false, true, false],
    };

    let (a, b) = x.a_b();
    *a += 1;
    *b += 1.0;
}

原有的 a()、b() 和 c() 都以 &mut self 为接收者。每个返回的引用都会独占借用接收者;第一个引用还在使用时,Rust 就不允许再通过另一个访问器借用 x。让同一个方法返回多个字段的引用,Rust 就能在方法内部确认它们指向不同字段。

同时借用 Vec 中的不同元素

连续调用两次 x.c(index),无法安全地证明两个索引不同。要借用两个不同位置,可以用 split_at_mut 将切片拆成互不重叠的部分:

let (left, right) = x.c.split_at_mut(3);
let c0: &mut bool = &mut left[0];
let c3: &mut bool = &mut right[0];

*c0 = false;
*c3 = true;

split_at_mut(3) 将索引 0..3 和 3.. 分开,所以 left[0] 和 right[0] 分别对应原向量中的索引 0 和 3。调用前,向量长度至少要为 4,否则索引会越界。如果索引来自运行时输入,还要检查它们是否在范围内、是否不同,再按较小的索引拆分切片。

嵌套结构体中的引用与释放

这取决于方法返回的引用绑定到哪个生命周期。如果方法通过 &mut self 返回引用,返回值通常受这次对结构体 4 的可变借用约束。只要还在使用返回的引用,就不能释放或再次可变借用结构体 4。

如果结构体 4 保存着指向外部数据的可变引用,并通过类型参数保留了该数据的生命周期,可以设计一个消费 self 并将引用返回给调用者的方法。简化形式如下:

struct S1 {
    value: i32,
}

struct S2<'a> {
    s1: &'a mut S1,
}

struct S3<'a> {
    s2: &'a mut S2<'a>,
}

struct S4<'a> {
    s3: &'a mut S3<'a>,
}

impl<'a> S4<'a> {
    fn into_value(self) -> &'a mut i32 {
        &mut self.s3.s2.s1.value
    }
}

into_value 会消费 S4。返回值的生命周期标为 'a,对应嵌套引用指向的数据,而不是调用者手中的 S4。因此,调用者可以保留返回的引用,让 S4 随后离开作用域。如果实际结构体使用了不同的生命周期参数,返回类型需要根据真实的引用关系调整。Rust 仍会禁止通过同一条可变引用链创建重叠的可变借用。

如果要同时返回多个内部成员的可变引用,应在同一个方法中拆分互不重叠的字段,并在方法签名中明确表示这些引用共享的生命周期。如果结构体 4 还需要继续使用,就不能把同一条独占可变引用链同时交给调用者。此时可以一次性消费结构体 4,或只在它的借用范围内使用返回的引用。

备注:内容仅供参考。