【问题标题】:How to create a trait that return a flatmap如何创建返回平面图的特征
【发布时间】:2020-11-30 17:14:21
【问题描述】:

我正在尝试创建一个从字符串扩展迭代器并返回平面地图的特征,这是我目前得到的结果

trait WordsExt<'a, F>: Iterator<Item = &'a str>
where
    Self: Sized,
    F: FnMut(&'a str) -> Split<'a, &'a str>,
{
    fn words(self) -> FlatMap<Self, Split<'a, &'a str>, F> {
        self.flat_map(|x: &'a str| x.split(" "))
    }
}

我被困在闭包类型上。

我也试过了

struct Words<'a, I>
where
    I: Iterator<Item = &'a str>,
{
    inner: I,
}

trait WordsExt<'a>: Iterator<Item = &'a str>
where
    Self: Sized,
{
    fn words(
        self,
    ) -> Words<'a, FlatMap<Self, Split<'a, &'a str>, Fn(Self::Item) -> Split<'a, &'a str>>>
    {
        Words {
            inner: self.flat_map(|x: &'a str| x.split(" ")),
        }
    }
}

我每次都遇到这个问题。我需要返回一个特征。当我在一个函数中时,我可以使用impl Trait 语法。但是当表达一个特质时,我无法表达这一点。据我所知,我能得到的更接近的是使用泛型,以便方法在调用时被单态化。但是我需要让用户选择具体的类型。在这种情况下,闭包是实现细节,它不应该泄露给用户。

我遇到了这个答案How can I add new methods to Iterator?

在这种情况下,OP 用例有一个内部状态。就我而言,我只想创建一个别名i.words() -&gt; i.flat_map(|x| x.split(" "))

我知道连贯性,因此我可能需要在 Iterator 上创建一个包装器,因为 Iterator 不在我的 crate 下。这是第二次尝试。

我可以通过简单的方式实现一个函数

fn words<'a>(i: impl Iterator<Item = &'a str>) -> impl Iterator<Item = &'a str> {
    i.flat_map(|x| x.split(" "))
}

但我无法用 trait 语法表达相同的意思,因为 trait 中没有 impl Trait 语法。所以......我有两个选择,动态调度和泛型,它们都不理想。更进一步。由于这些结构没有大小,我不能对其使用静态调度,所以我被困在简单的动态调度上

下面的结构无效

struct Words<'a>(Iterator<Item = &'a str>);

最后,我希望给定一个函数F(X),我总是能够重构它以编写一个X.F(),但这似乎不是真的,因为虽然我能够编写fn f(x) -&gt; impl Y,但我是无法表达trait X { fn (self) -&gt; impl Y },终于不再重复泛型或动态调度。

我试图用一种流畅的语法编写迭代器组合器:iterator.comb1().comb2().comb3()

【问题讨论】:

    标签: rust


    【解决方案1】:

    我通过如下更改来编译你的代码:

    trait WordsExt<'a>: Iterator<Item = &'a str>
    where
      Self: Sized,
    {
      fn words(self) -> FlatMap<Self, Split<'a, &'a str>, fn(&'a str) -> Split<'a, &'a str>> {
        self.flat_map(|x: &'a str| x.split(" "))
      }
    }
    

    诀窍是用实际的函数类型替换函数特征对象。

    【讨论】:

    • Fn和fn有什么区别?
    • 顺便谢谢你。每次我遇到这样的问题就像解决一个数学难题
    • Fn 是一个特征,而 fn 是一个类型。由于您知道要将哪个函数应用于您的元素,因此您不需要任何通用的Fn
    • fn(&amp;'a str) -&gt; Split&lt;'a, &amp;'a str&gt; 是一个函数 pointer 类型,这意味着使用它会比使用函数类型本身(这就是 impl Trait 的工作原理)产生(小的)性能损失,但目前在 trait 中是不可能的)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-07
    • 1970-01-01
    • 2020-12-20
    • 1970-01-01
    相关资源
    最近更新 更多