Rust RPIT AFIT 基本概念介绍

2025-01-12 rust

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;
}