如何定义接收HasPosition2D可迭代对象引用的泛型函数及类型别名?
Base Trait and Implementation
First, here's the core HasPosition2D trait and its implementation for (i32, i32):
trait HasPosition2D { fn x(&self) -> i32; fn y(&self) -> i32; } impl HasPosition2D for (i32, i32) { fn x(&self) -> i32 { self.0 } fn y(&self) -> i32 { self.1 } }
Original print_all (Moves Container)
This function consumes the input container to iterate over its items:
fn print_all<I>(iterable: I) where I: IntoIterator, I::Item: HasPosition2D, { for pos in iterable { println!("x: {}, y: {}", pos.x(), pos.y()); } }
1. Fixed print_all2 (Immutable Reference)
The key fix is ensuring the immutable reference to the container implements IntoIterator, yielding items that are references to HasPosition2D:
// Fixed print_all2: accepts immutable reference, no container movement fn print_all2<I>(iterable: &I) where &I: IntoIterator, <&I as IntoIterator>::Item: HasPosition2D, { for pos in iterable { println!("x: {}, y: {}", pos.x(), pos.y()); } }
2. Mutable Reference Version (print_all_mut)
This function takes a mutable reference, allowing iteration over mutable references to items (useful if you need to modify positions):
// Function for mutable container references fn print_all_mut<I>(iterable: &mut I) where &mut I: IntoIterator, <&mut I as IntoIterator>::Item: HasPosition2D, { for pos in iterable { println!("x: {}, y: {}", pos.x(), pos.y()); // Uncomment if you add mutable methods to HasPosition2D // pos.set_x(pos.x() + 1); } }
3. Type Aliases with Nightly Features
To simplify repeated trait bounds, use the nightly features trait_alias and type_alias_impl_trait:
Enable Features
Add these to the top of your crate:
#![feature(trait_alias)] #![feature(type_alias_impl_trait)]
Trait Aliases for Bounds
Create reusable aliases for common iterator trait bounds:
// Alias for iterables that yield owned HasPosition2D items (moves container) trait IterablePosOwned = IntoIterator<Item: HasPosition2D>; // Alias for iterables from immutable references (yields &HasPosition2D) trait IterablePosRef<'a> = IntoIterator<Item: &'a HasPosition2D>; // Alias for iterables from mutable references (yields &mut HasPosition2D) trait IterablePosMut<'a> = IntoIterator<Item: &'a mut HasPosition2D>;
Use Aliases in Functions
Refactor the earlier functions to use these aliases for cleaner code:
fn print_all<I: IterablePosOwned>(iterable: I) { for pos in iterable { println!("x: {}, y: {}", pos.x(), pos.y()); } } fn print_all2<'a, I>(iterable: &'a I) where &'a I: IterablePosRef<'a>, { for pos in iterable { println!("x: {}, y: {}", pos.x(), pos.y()); } } fn print_all_mut<'a, I>(iterable: &mut I) where &'a mut I: IterablePosMut<'a>, { for pos in iterable { println!("x: {}, y: {}", pos.x(), pos.y()); } }
Opaque Type Aliases (type_alias_impl_trait)
For opaque iterator types (e.g., return types), use type_alias_impl_trait to create reusable type aliases:
// Opaque type alias for immutable position iterators type PosRefIterator<'a> = impl Iterator<Item = &'a dyn HasPosition2D>; // Function using the opaque type alias fn get_pos_ref_iter<'a>(container: &'a [(i32, i32)]) -> PosRefIterator<'a> { container.iter().map(|p| p as &dyn HasPosition2D) }
Example Usage
fn main() { let positions = vec![(1, 2), (3, 4), (5, 6)]; print_all2(&positions); // Safe to use positions after this let mut mutable_positions = vec![(7, 8), (9, 10)]; print_all_mut(&mut mutable_positions); }
内容的提问来源于stack exchange,提问作者Blue7

