< 返回版块

tottiandlsg 发表于 2022-11-30 10:28

向诸位大神请教一下。 最近在使用filter方法时看了一下标准库的实现。 函数在库中的定义fn filter(self, predicate: P) -> Filter<Self, P> 返回的类型是一个Filter

但是在使用时发现其返回类型是一个impl接口 let iter: impl Iterator<Item = &i32> = lsg_a.iter().filter(|x| **x > 0);

vscode提示的类型是impl Iterator<Item = &i32>

不太理解是如何转换的,求大家指教一下,谢谢

评论区

写评论
作者 tottiandlsg 2022-12-01 16:18

感谢您的详细解答,获益匪浅

--
👇
苦瓜小仔:

原因在于 闭包 是无法命名(或者匿名)的类型。比如 RA 会告诉你一个变量类型为 let var: Filter<Iter<i32>, |&&i32| -> bool>,但你无法“指名”这个类型。

对于所有匿名类型,使用者可以利用泛型(单态化)或者类型擦除。

Ra 使用了 impl trait type,所以你看到的是 impl Iterator<Item = &i32>

考虑以下函数:

fn take_filter(filter: /* 这里应该写什么类型 */) { }

你无法写 Filter<Iter<i32>, |&&i32| -> bool>,因为 |&&i32| -> bool 不是 你能写的 类型,那么 Filter<Iter<i32>, F> where F: FnMut(&&i32) -> bool 呢?你需要更复杂的签名。

fn take_filter<'iter, F: FnMut(&&'iter i32) -> bool>(filter: Filter<Iter<'iter, i32>, F>) { }

但这显然不需要,引入的精确类型并没有多大帮助:因为 impl trait type 会单态化,最终类型依然是精确的。

fn take_iter<'a>(filter: impl Iterator<Item = &'a i32>) { } // 这是静态分发,而且更通用 

playground

苦瓜小仔 2022-11-30 11:18

原因在于 闭包 是无法命名(或者匿名)的类型。比如 RA 会告诉你一个变量类型为 let var: Filter<Iter<i32>, |&&i32| -> bool>,但你无法“指名”这个类型。

对于所有匿名类型,使用者可以利用泛型(单态化)或者类型擦除。

Ra 使用了 impl trait type,所以你看到的是 impl Iterator<Item = &i32>

考虑以下函数:

fn take_filter(filter: /* 这里应该写什么类型 */) { }

你无法写 Filter<Iter<i32>, |&&i32| -> bool>,因为 |&&i32| -> bool 不是 你能写的 类型,那么 Filter<Iter<i32>, F> where F: FnMut(&&i32) -> bool 呢?你需要更复杂的签名。

fn take_filter<'iter, F: FnMut(&&'iter i32) -> bool>(filter: Filter<Iter<'iter, i32>, F>) { }

但这显然不需要,引入的精确类型并没有多大帮助:因为 impl trait type 会单态化,最终类型依然是精确的。

fn take_iter<'a>(filter: impl Iterator<Item = &'a i32>) { } // 这是静态分发,而且更通用 

playground

songzhi 2022-11-30 11:08

实际上还是Filter,只是rust-analyzer显示成了impl xxx,因为可读性更好。

1 共 3 条评论, 1 页