gpt4 book ai didi

generics - 通用特征和生命周期的问题

转载 作者:行者123 更新时间:2023-12-03 11:36:29 25 4
gpt4 key购买 nike

我在更大的上下文中遇到了通用特征的问题,并尝试将其缩小到这个较小的问题。我想要以下功能:

fn count<I, S, T>(pattern: T, item:I) -> usize
where
I: Atom,
S: Iterator<Item = I>
T: Atoms<I, S>,
{
pattern.atoms().filter(|i| i == &item).count()
}
该函数应传递两个参数:
  • pattern:Atoms<...>它有一个工厂方法 atom 返回一个原子迭代器
  • item:Atom这是原子迭代器中应该计算的项目

  • 该函数应该对两个参数都是通用的(具有 pattern.atoms() 必须返回具有与 item 相同类型的项目的迭代器的约束),例如:
    count(Atoms<u8, std::str::Bytes<'_>>, u8) -> usize
    count(Atoms<char, std::str::Chars<'_>>, char) -> usize
    count(Atoms<u8, std::io::Bytes>, u8) -> usize
    对于 Atom,我尝试了这种方法:
    pub trait Atom: Copy + Eq + Ord + Display + Debug {}
    impl Atom for char {}
    impl Atom for u8 {}
    接下来我从 Atoms 开始,首先没有生命周期:
    pub trait Atoms<I, S>
    where
    S: Iterator<Item = I>,
    I: Atom,
    {
    fn atoms(&self) -> S;
    }
    我尝试为 str 实现此功能使用 std::str::Bytes<'a>作为迭代器。因此编译器会遗漏生命周期注解 &'a self在原子中。因此,我用生命周期改进了这种方法,并提出了以下代码:
    pub trait Atoms<'a, I, S>
    where
    S: Iterator<Item = I> + 'a,
    I: Atom,
    {
    fn atoms(&'a self) -> S;
    }

    impl<'a> Atoms<'a, u8, std::str::Bytes<'a>> for &str {
    fn atoms(&'a self) -> std::str::Bytes<'a> {
    self.bytes()
    }
    }

    fn count<'a, I, S, T>(pattern: T, item: I) -> usize
    where
    I: Atom,
    S: Iterator<Item = I> + 'a,
    T: Atoms<'a, I, S>,
    {
    pattern.atoms().filter(|i| *i == item).count() //<--- compiler complains
    }
    Playground-Link
    现在编译器提示 the parameter type 电话 may not live long enough, ... consider adding ... T:'a .我不明白这个问题。该提示甚至不起作用(另一个终生问题随之而来)所以我不知道我的误解是什么。有人可以帮助我理解(甚至解决)这个问题吗?

    最佳答案

    atoms功能需要self终生借用'a .如果你给这个函数一个生命周期不长的类型,这个函数就不能正常工作。
    例如,类型 &'b T生命周期为 'b .如果您实现 Atoms对于 &'b T'b'a 短,您一定不能调用atoms功能。这就是为什么你必须约束 T至少活到 'a .
    Rust 知道这一点并自动对 atoms 执行此操作功能:

    fn atoms(&'a self) -> std::str::Chars<'a>
    where
    Self: 'a,
    { self.chars() }
    但是当你尝试在另一个函数中使用该函数时,Rust 需要你自己添加这个键。这就是为什么您需要为 count 添加它的原因。功能。
    第二个问题
    您的 Atom trait 不需要携带 'a生命周期。你的第一种方法是正确的。
    pub trait Atoms<S>
    where
    S: Iterator,
    S::Item: Atom,
    {
    fn atoms(&self) -> S;
    }
    (请注意,我删除了通用参数 I 并将其替换为 S::Item 。这是可能的,因为 ItemIterator 的关联类型。除了更清晰之外没有任何改变。)
    之后,实现非常简单。
    // Note the `&'a str` here, this was missing on your implementation but it is actually
    // needed. If you think about it, the bytes that are returned are part of the `&str`
    // so they must live at least as long as the reference.
    impl<'a> Atoms<std::str::Bytes<'a>> for &'a str {
    // The difference is here. You don't need to chose a lifetime for `&self`.
    // A longer lifetime than `'a` would be ok. That would be a reference to
    // a reference of a lifetime of `'a`.
    //
    // `self` is `&'a str` here.
    // so `&self` is `&&'a str`
    //
    // What you did was telling Rust that that second reference needed to live
    // as long as `'a`. Meaning `&'a &'a str`. But this was wrong. That reference
    // must be able to live longer than `'a`.
    fn atoms(&self) -> std::str::Bytes<'a> {
    self.bytes()
    }
    }
    之后, count功能按预期工作:
    fn count<S, T>(pattern: T, item: I) -> usize
    where
    S::Item: Atom,
    S: Iterator,
    T: Atoms<S>,
    {
    pattern.atoms().filter(|i| *i == item).count() //<--- compiler does not complain anymore ;)
    }

    关于generics - 通用特征和生命周期的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65618771/

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