关于Rust Iterator的all方法使用FnMut及元素修改失效的疑问
Rust Iterator::all 常见问题解析
一、为什么示例中x = "cc"的赋值不生效?
先看你的代码:
fn main() { let a = ["as", "zz"]; let mut iter = a.iter(); iter.all(|&(mut x)| {x = "cc"; true}); for z in a.iter(){ println!("{z}"); } }
运行后数组元素没有变化,核心原因有两个:
你修改的是局部变量副本:
a.iter()生成的是不可变迭代器,迭代的是数组元素的不可变引用。闭包参数&(mut x)是模式匹配,把引用指向的&str值拷贝到了局部变量x里——你修改的只是这个临时的局部变量,和原数组里的元素完全无关。原数组本身不可变:就算你想修改原元素,
let a = ["as", "zz"]定义的是不可变数组,本身就不允许修改元素。如果要修改,得先把数组声明为mut,再用iter_mut()获取可变迭代器,闭包里拿到可变引用后才能修改原元素(虽然这违背all方法的设计语义,但语法上可行)。
比如下面的代码就能修改原数组元素(仅作语法演示,不推荐实际使用all做修改):
fn main() { let mut a = ["as", "zz"]; let mut iter = a.iter_mut(); iter.all(|x| { *x = "cc"; true }); for z in a.iter(){ println!("{z}"); } }
这段代码会输出两次cc,因为闭包里修改的是原数组元素的可变引用指向的内容。
二、为什么all接受FnMut而非Fn类型的闭包?
all的设计目的是验证所有元素是否满足条件,但它选择FnMut是为了兼容更多使用场景,而非限制:
FnMut是Fn的超 trait,所有Fn类型的闭包都能自动适配FnMut,所以接受FnMut不会影响纯函数式的验证场景。- 允许用户在闭包里修改捕获的外部状态,比如统计验证过程中的中间数据。举个例子:
fn main() { let nums = [1,2,3,4,5]; let mut valid_count = 0; let all_even = nums.iter().all(|&n| { if n % 2 == 0 { valid_count += 1; true } else { false } }); println!("All even? {}, Valid count: {}", all_even, valid_count); }
这里闭包需要修改外部的valid_count变量,必须用FnMut类型。all支持这种用法,既保留了纯验证场景的兼容性,又给用户提供了额外的灵活性。
内容的提问来源于stack exchange,提问作者Rohit Sharma
相关产品推荐
相关产品推荐

