RPIT
Return Position Impl Trait, RPIT
允许函数返回类型中使用 impl Trait
的方式替代具体的类型,如下是两个简单示例,分别返回迭代和闭包。
fn odd(start: u32, end: u32) -> impl Iterator<Item = u32> {
(start..end).filter(|i| i % 2 != 0)
}
fn double() -> impl Fn(i32) -> i32 {
|x| x * 2
}
fn main() {
for v in odd(0, 10) {
println!("{v}");
}
println!("Double 3 is {}", double()(3));
}
更多的内容可以参考 RFC 1522 中的介绍。
RPITIT
Return Position Impl Trait In Trait, RPITIT
与上述的方式类似,只是在 Trait
中定义,其依赖 Generic Associated Types, GAT
关联类型。
GAT 允许在关联类型中使用泛型,包括类型、生命周期、常量等。
如下是简单示例。
trait NewIntoIterator {
type Item;
fn new_into_iter(self) -> impl Iterator<Item = Self::Item>;
}
impl NewIntoIterator for Vec<u32> {
type Item = u32;
fn new_into_iter(self) -> impl Iterator<Item = Self::Item> {
self.into_iter()
}
}
fn main() {
let data: Vec<u32> = [1, 2, 3].to_vec();
for v in data.new_into_iter() {
println!("{v}");
}
}
上述实际上是基于 GAT 实现的语法糖,详见 RFC 3425 中的介绍。
AFIT
常规的 async
函数的返回值会解糖为 impl Future<Output = return_type>
类型,也就是 RPIT
的实现,例如。
async fn hello() -> i32 {
1
}
fn hello() -> impl Future<Output = i32> {
async { 1 }
}
而 Async fn In Trait, AFIT
会解糖到 RPITIT
实现,这也是解决了异步中的问题,可以参考 why async fn in traits are hard,例如。
trait Database {
async fn fetch_data(&self) -> String;
}