gpt4 book ai didi

rust - 在迭代器上创建方法,在 Rust 中返回迭代器

转载 作者:行者123 更新时间:2023-12-05 01:12:27 24 4
gpt4 key购买 nike

我想定义一个懒惰的square()没有不必要的运行时开销(没有 dyn 关键字)的方法,可以在任何 Iterable<Item = u8> 上调用并返回另一个 Iterable<Item = u8> ,像这样:

fn main() {
vec![1, 2, 3, 4, 5]
.iter()
.filter(|x| x > 1)
.squared()
.filter(|x| x < 20);
}

我知道如何定义 squared()作为一个独立的功能:

fn squared<I: Iterator<Item = u8>>(iter: I) -> impl Iterator<Item = u8> {
iter.map(|x| x * x)
}

Iterator<Item = u8> 上定义该方法不过,我必须先定义一个 trait .
这就是我挣扎的地方 — 特质无法使用 impl返回值中的关键字。

我正在寻找类似以下的东西,但它不起作用:

trait Squarable<I: Iterator<Item = u8>> {
fn squared(self) -> I;
}

impl<I, J> Squarable<I> for J
where
I: Iterator<Item = u8>,
J: Iterator<Item = u8>,
{
fn squared(self) -> I {
self.map(|x| x * x)
}
}

我曾多次尝试解决该问题,但都失败了,包括更改 squared 的返回类型。至 Map<u8, fn(u8) -> u8>并修补 IntoIterable s,但到目前为止没有任何效果。任何帮助将不胜感激!

最佳答案

首先,您的输出迭代器可能应该是关联类型而不是特征参数,因为该类型是特征的输出(它不是调用者可以控制的)。

trait Squarable {
type Output: Iterator<Item = u8>;
fn squared(self) -> I;
}

话虽如此,有几种不同的可能方法可以解决这个问题,每种方法都有不同的优点和缺点。

使用特征对象

第一个是使用特征对象,例如 dyn Iterator<Item = u8> , 在运行时删除类型。这需要轻微的运行时成本,但绝对是当今稳定 Rust 中最简单的解决方案:

trait Squarable {
fn squared(self) -> Box<dyn Iterator<Item = u8>>;
}

impl<I: 'static + Iterator<Item = u8>> Squarable for I {
fn squared(self) -> Box<dyn Iterator<Item = u8>> {
Box::new(self.map(|x| x * x))
}
}

使用自定义迭代器类型

在稳定的 Rust 中,从 trait 用户的角度来看,这绝对是最干净的,但是它需要更多的代码来实现,因为你需要编写自己的迭代器类型。然而,对于一个简单的 map迭代器这是非常简单的:

trait Squarable: Sized {
fn squared(self) -> SquaredIter<Self>;
}

impl<I: Iterator<Item = u8>> Squarable for I {
fn squared(self) -> SquaredIter<I> {
SquaredIter(self)
}
}

struct SquaredIter<I>(I);

impl<I: Iterator<Item = u8>> Iterator for SquaredIter<I> {
type Item = u8;
fn next(&mut self) -> Option<u8> {
self.0.next().map(|x| x * x)
}
}

使用显式 Map类型
<I as Iterator>::map(f)有一个类型 std::iter::Map<I, F> ,所以如果类型 F的映射函数是已知的,我们可以显式使用该类型,而无需运行时成本。这确实将特定类型公开为函数返回类型的一部分,这使得将来在不破坏依赖代码的情况下更难替换。在大多数情况下,函数也不为人所知;在这种情况下,我们可以使用 F = fn(u8) -> u8但是由于该函数不保留任何内部状态(但通常不起作用)。

trait Squarable: Sized {
fn squared(self) -> std::iter::Map<Self, fn(u8) -> u8>;
}

impl<I: Iterator<Item = u8>> Squarable for I {
fn squared(self) -> std::iter::Map<Self, fn(u8) -> u8> {
self.map(|x| x * x)
}
}

使用关联类型

上面的一个替代方法是给特征一个关联类型。这仍然具有必须知道函数类型的限制,但自 Map<...> 以来它更通用一点。 type 与实现相关,而不是 trait 本身。

trait Squarable {
type Output: Iterator<Item = u8>;
fn squared(self) -> Self::Output;
}

impl<I: Iterator<Item = u8>> Squarable for I {
type Output = std::iter::Map<Self, fn(u8) -> u8>;
fn squared(self) -> Self::Output {
self.map(|x| x * x)
}
}

使用 impl在关联类型

这类似于上面的“使用关联类型”,但您可以完全隐藏实际类型,除了它是一个迭代器这一事实。我个人认为这是首选的解决方案,但不幸的是它仍然不稳定(这取决于 type_alias_impl_trait 功能),因此您只能在夜间 Rust 中使用它。

#![feature(type_alias_impl_trait)]

trait Squarable {
type Output: Iterator<Item = u8>;
fn squared(self) -> Self::Output;
}

impl<I: Iterator<Item = u8>> Squarable for I {
type Output = impl Iterator<Item = u8>;
fn squared(self) -> Self::Output {
self.map(|x| x * x)
}
}

关于rust - 在迭代器上创建方法,在 Rust 中返回迭代器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60552911/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com