Rust中如何在zip迭代器循环内对原类型执行可变操作?
问题:Rust中zip迭代器时修改原类型导致借用冲突
问题代码
#[derive(Default, Debug)] struct Data { pub values: [bool; 4], } fn main() { let mut d = Data::default(); println!("{:?}", d); for (i, (v, dv)) in [true, false, false, true].iter().zip(d.values.iter()).enumerate() { if *v != *dv { d.values[i] = *v; } } println!("{:?}", d); }
编译错误
Compiling playground v0.0.1 (/playground) error[E0506]: 无法赋值给 `d.values[_]`,因为它已被借用 --> src/main.rs:11:13 | 9 | for (i, (v, dv)) in [true, false, false, true].iter().zip(d.values.iter()).enumerate() { | ------------------------------------------------------------------ | | | | | 此处借用了 `d.values[_]` | 后续使用了该借用 10 | if *v != *dv { 11 | d.values[i] = *v; | ^^^^^^^^^^^^^^^^ 对已借用的 `d.values[_]` 进行赋值 有关此错误的更多信息,请尝试 `rustc --explain E0506`。 error: 由于之前的错误,无法编译 `playground`
原因分析
Rust的借用检查规则禁止同一变量同时存在不可变借用和可变借用:
d.values.iter()创建了不可变迭代器,持有d.values的不可变借用,该借用在整个循环周期内有效。- 循环内的
d.values[i] = *v尝试获取d.values的可变借用,与之前的不可变借用冲突,导致编译失败。
解决方案
方案1:直接索引遍历(无需迭代器zip)
通过索引访问两个数组,避免创建持续的借用:
#[derive(Default, Debug)] struct Data { pub values: [bool; 4], } fn main() { let mut d = Data::default(); println!("{:?}", d); let src = [true, false, false, true]; for i in 0..src.len() { let v = src[i]; if v != d.values[i] { d.values[i] = v; } } println!("{:?}", d); }
方案2:使用可变迭代器直接修改(推荐)
用iter_mut()获取目标数组的可变引用迭代器,直接与源迭代器zip后修改,无需额外索引:
#[derive(Default, Debug)] struct Data { pub values: [bool; 4], } fn main() { let mut d = Data::default(); println!("{:?}", d); for (v, dv) in [true, false, false, true].iter().zip(d.values.iter_mut()) { if *v != *dv { *dv = *v; } } println!("{:?}", d); }
这种方式符合Rust迭代器的设计风格,无需手动处理索引,同时避免了借用冲突。
方案3:复制目标数组(适用于小型Copy类型)
利用数组的Copy特性,复制目标数组到循环中,避免持有原数组的借用:
#[derive(Default, Debug)] struct Data { pub values: [bool; 4], } fn main() { let mut d = Data::default(); println!("{:?}", d); let src = [true, false, false, true]; for (i, (&v, dv)) in src.iter().zip(d.values).enumerate() { if v != dv { d.values[i] = v; } } println!("{:?}", d); }
内容的提问来源于stack exchange,提问作者RobotHerder
相关产品推荐
相关产品推荐

