是否可以编写一个函数来修改
struct
成员,以便可以将其与 Vec
和 HashMap::values()
一起使用?
这就是我到目前为止所想到的:
use std::collections::HashMap;
struct Foo {
x: i32,
}
fn process_collection<T>(collection: &mut T)
where
T: IntoIterator<Item = Foo>,
for<'a> &'a mut T: IntoIterator<Item = &'a mut Foo>,
{
for item in collection.into_iter() {
item.x = 5;
}
}
fn main() {
let mut numbers = vec![Foo { x: 1 }, Foo { x: 2 }];
// Set all .x members to 5.
process_collection(&mut numbers);
for item in &numbers {
println!("item after: {}", item.x);
}
let mut data: HashMap<String, Foo> = HashMap::new();
data.insert("One".to_string(), Foo {x: 1} );
data.insert("Two".to_string(), Foo {x: 2});
// This does not compile.
process_collection(&mut data.values());
}
values
迭代对值的 immutable 引用,如果您需要独占引用才能改变值,则必须使用 values_mut
。
此外,在
&mut T
中写出可变引用是极其有限的,并且根本不允许 ValuesMut
(对值的可变引用的迭代器)(它也不实现 IntoIterator
,而只是采用 T: IntoIterator<&mut Foo>
:
fn process_collection<'a, T>(collection: T)
where
T: IntoIterator<Item = &'a mut Foo>,
{
for item in collection.into_iter() {
item.x = 5;
}
}
fn main() {
let mut numbers = vec![Foo { x: 1 }, Foo { x: 2 }];
// Set all .x members to 5.
process_collection(&mut numbers);
for item in &numbers {
println!("item after: {}", item.x);
}
let mut data: HashMap<String, Foo> = HashMap::new();
data.insert("One".to_string(), Foo {x: 1} );
data.insert("Two".to_string(), Foo {x: 2});
process_collection(data.values_mut());
for item in data.values() {
println!("item after: {}", item.x);
}
}
要修改适当的元素,您只需要一个具有可变访问权限的迭代器:
fn process_collection<'a, T>(collection: T)
where
T: IntoIterator<Item = &'a mut Foo>,
{
for item in collection {
item.x = 5;
}
}
您可以使用
Vec<Foo>
进行呼叫,如下所示:
process_collection(&mut numbers);
或者使用
HashMap<_, Foo>
中的值,如下所示:
process_collection(data.values_mut());
注意更改:
T: IntoIterator
和 &mut T: IntoIterator
。尽管集合通常具有这两种实现,但这不是必需的,也不适用于 HashMap
的值。values_mut()
而不是仅 values()
,因为后者仅提供不可变引用。collection
作为自有值传递,而不是作为可变引用传递,因为它更惯用。