如何从Rust trait方法中返回std::iter::Map类型?
问题描述
我有一个元组向量:
let l = vec![(0, 1), (2, 3)];
我想获取一个提取每个元组第一个元素的std::iter::Map。常规写法可以正常工作:
let m: std::iter::Map<_, _> = l.iter().map(|e| e.0);
现在我希望扩展Iterator trait,让以下代码生效:
let m: std::iter::Map<_, _> = l.iter().tuple_first();
尝试1:返回impl Iterator
我尝试在 trait 方法中返回impl Iterator,但编译失败:
trait TupleExtractor<'a, T1: 'a, T2: 'a>: Iterator<Item = &'a (T1, T2)> { fn tuple_first(self) -> impl Iterator<Item = &'a T1>; } impl<'a, T1: 'a + Copy, T2: 'a, I> TupleExtractor<'a, T1, T2> for I where I: Iterator<Item = &'a (T1, T2)>, { fn tuple_first(self) -> impl Iterator<Item = &'a T1> { self.map(|e| e.0) } }
错误信息:
`impl Trait` only allowed in function and inherent method return types, not in trait method return types
尝试2:显式返回std::iter::Map
我改为显式返回std::iter::Map类型,但依然编译失败:
trait TupleExtractor<'a, T1: 'a, T2: 'a>: Iterator<Item = &'a (T1, T2)> { fn tuple_first( self, ) -> std::iter::Map<impl Iterator<Item = &'a (T1, T2)>, impl FnMut(&'a (T1, T2)) -> T1>; } impl<'a, T1: 'a + Copy, T2: 'a, I> TupleExtractor<'a, T1, T2> for I where I: Iterator<Item = &'a (T1, T2)>, { fn tuple_first(self) -> std::iter::Map<I, impl FnMut(&'a (T1, T2)) -> T1> { self.map(|e| e.0) } }
尝试3:将Map的类型参数设为 trait 泛型参数
我尝试把Map的两个类型参数加到 trait 的泛型列表中,还是编译失败:
trait TupleExtractor<'a, T1: 'a, T2: 'a, A, B>: Iterator<Item = &'a (T1, T2)> { fn tuple_first(self) -> std::iter::Map<A, B>; } impl<'a, T1: 'a + Copy, T2: 'a, I, F> TupleExtractor<'a, T1, T2, I, F> for I where I: Iterator<Item = &'a (T1, T2)>, F: FnMut(&'a (T1, T2)) -> T1, { fn tuple_first(self) -> std::iter::Map<I, F> { self.map(|e: &'a (T1, T2)| e.0) } }
错误信息:
= note: expected type parameter `F` found closure `[closure@src/main.rs:38:18: 38:35]` = help: every closure has a distinct type and so could not always match the caller-chosen type of parameter `F`
解决方法:使用关联类型
要在 trait 方法中返回具体的Map类型,核心是用关联类型定义返回值的类型参数,让 trait 实现方决定具体类型,而非调用方。
基础版本代码
use std::iter::Map; trait TupleExtractor<'a, T1: 'a, T2: 'a>: Iterator<Item = &'a (T1, T2)> { // 定义关联类型,代表Map的闭包类型 type MapFn: FnMut(&'a (T1, T2)) -> &'a T1; fn tuple_first(self) -> Map<Self, Self::MapFn>; } impl<'a, T1: 'a, T2: 'a, I> TupleExtractor<'a, T1, T2> for I where I: Iterator<Item = &'a (T1, T2)>, { // 指定关联类型为当前闭包的具体类型 type MapFn = impl FnMut(&'a (T1, T2)) -> &'a T1; fn tuple_first(self) -> Map<Self, Self::MapFn> { self.map(|e| &e.0) } } fn main() { let l = vec![(0, 1), (2, 3)]; let m: Map<_, _> = l.iter().tuple_first(); for val in m { println!("{}", val); } }
代码说明
- 关联类型:在 trait 中定义
type MapFn,用来表示Map的闭包类型,每个实现可以自行指定该类型,无需调用方提前确定。 - 返回具体类型:方法返回
Map<Self, Self::MapFn>,其中Self是当前迭代器类型,Self::MapFn是闭包类型,由实现方指定。 - 闭包调整:将闭包返回值从
e.0改为&e.0,返回引用类型,避免要求T1实现Copy(如果需要返回值而非引用,可改回e.0并添加Copy约束)。
泛化版本:支持值和引用元组
如果希望方法同时处理所有权迭代器和引用迭代器,可以进一步泛化 trait:
use std::iter::Map; trait TupleFirst: Iterator { type Output; type MapFn: FnMut(Self::Item) -> Self::Output; fn tuple_first(self) -> Map<Self, Self::MapFn>; } // 处理引用元组的迭代器 impl<'a, T1, T2, I> TupleFirst for I where I: Iterator<Item = &'a (T1, T2)>, { type Output = &'a T1; type MapFn = impl FnMut(&'a (T1, T2)) -> &'a T1; fn tuple_first(self) -> Map<Self, Self::MapFn> { self.map(|e| &e.0) } } // 处理值元组的迭代器 impl<T1, T2, I> TupleFirst for I where I: Iterator<Item = (T1, T2)>, { type Output = T1; type MapFn = impl FnMut((T1, T2)) -> T1; fn tuple_first(self) -> Map<Self, Self::MapFn> { self.map(|(a, _)| a) } } fn main() { let l = vec![(0, 1), (2, 3)]; // 引用迭代器 let m1: Map<_, _> = l.iter().tuple_first(); // 所有权迭代器 let m2: Map<_, _> = l.into_iter().tuple_first(); }
内容的提问来源于stack exchange,提问作者ynn
相关产品推荐
相关产品推荐

