generics - 如何在Rust中实现装饰器?

标签 generics rust iterator lifetime borrow-checker

我正在学习Rust,并且坚持使用玩具示例。我已经阅读了有关生存期的文档,此post以及有关Stack Overflow的一系列问题。我已经花了一个多星期的时间,但仍然遇到困难,因此我决定向社区寻求帮助。
我有一个通用的特性BookSide,它返回BookIterator(扩展了通常的Iterator)。我对BookSideBookIterator有两种实现:ArrayBookSideCommissionBookSide

  • 第一个是有状态的。它的引擎盖下有一个Vec
  • 第二个是无状态的:它包装了其他BookSide

  • 我的目标只是简单地编译整个过程。我正在解决问题,并遵循编译器的建议。此过程导致以下代码。
    use std::marker::PhantomData;
    
    fn main() {
        println!("Hello, world!");
    }
    
    // traits
    
    pub trait BookIterator<'a>: Iterator<Item=f64> {}
    
    pub trait BookSide<'a> {
        type BookIteratorType: BookIterator<'a>;
    
        fn book_iterator(&self) -> Self::BookIteratorType;
    }
    
    // implementation 1: stateful
    
    pub struct ArrayBookSide {
        quotes: Vec<f64>,
    }
    
    pub struct ArrayBookSideIterator<'a> {
        quotes_iter: std::slice::Iter<'a, f64>,
    }
    
    impl<'a> BookSide<'a> for ArrayBookSide {
        type BookIteratorType = ArrayBookSideIterator<'a>;
    
        fn book_iterator(&self) -> Self::BookIteratorType {
            ArrayBookSideIterator { quotes_iter: self.quotes.iter() }
        }
    }
    
    impl<'a> Iterator for ArrayBookSideIterator<'a> {
        type Item = f64;
    
        fn next(&mut self) -> Option<Self::Item> {
            self.quotes_iter.next().map(|&quote| quote)
        }
    }
    
    impl<'a> BookIterator<'a> for ArrayBookSideIterator<'a> {}
    
    // implementation 2: delegating
    
    pub struct CommissionBookSide<'a, B>
        where B: BookSide<'a> {
        base_book_side: B,
        multiplier: f64,
        _marker: PhantomData<&'a B>,
    }
    
    impl<'a, B> CommissionBookSide<'a, B>
        where B: BookSide<'a> {
        pub fn new(base_book_side: B) -> CommissionBookSide<'a, B> {
            CommissionBookSide { base_book_side, multiplier: 1.1, _marker: PhantomData {} }
        }
    }
    
    impl<'a, B> BookSide<'a> for CommissionBookSide<'a, B>
        where B: BookSide<'a> {
        type BookIteratorType = CommissionIterator<'a, B::BookIteratorType>;
    
        fn book_iterator(&self) -> Self::BookIteratorType {
            CommissionIterator {
                base_iterator: self.base_book_side.book_iterator(),
                multiplier: self.multiplier,
                _marker: PhantomData {},
            }
        }
    }
    
    pub struct CommissionIterator<'a, BI>
        where BI: BookIterator<'a> {
        base_iterator: BI,
        multiplier: f64,
        _marker: PhantomData<&'a BI>,
    }
    
    impl<'a, BI> Iterator for CommissionIterator<'a, BI>
        where BI: BookIterator<'a> {
        type Item = BI::Item;
    
        fn next(&mut self) -> Option<Self::Item> {
            self.base_iterator.next().map(|quote| quote * self.multiplier)
        }
    }
    
    impl<'a, BI> BookIterator<'a> for CommissionIterator<'a, BI>
        where BI: BookIterator<'a> {}
    
    现在,我有以下编译错误。
    error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
      --> src/main.rs:31:58
       |
    31 |         ArrayBookSideIterator { quotes_iter: self.quotes.iter() }
       |                                                          ^^^^
       |
    note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 30:5...
      --> src/main.rs:30:5
       |
    30 | /     fn book_iterator(&self) -> Self::BookIteratorType {
    31 | |         ArrayBookSideIterator { quotes_iter: self.quotes.iter() }
    32 | |     }
       | |_____^
    note: ...so that reference does not outlive borrowed content
      --> src/main.rs:31:46
       |
    31 |         ArrayBookSideIterator { quotes_iter: self.quotes.iter() }
       |                                              ^^^^^^^^^^^
    note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 27:6...
      --> src/main.rs:27:6
       |
    27 | impl<'a> BookSide<'a> for ArrayBookSide {
       |      ^^
    note: ...so that the types are compatible
      --> src/main.rs:30:55
       |
    30 |       fn book_iterator(&self) -> Self::BookIteratorType {
       |  _______________________________________________________^
    31 | |         ArrayBookSideIterator { quotes_iter: self.quotes.iter() }
    32 | |     }
       | |_____^
       = note: expected `BookSide<'a>`
                  found `BookSide<'_>`
    
    我可能不应该使用PhantomData吗?对我来说,这看起来像是过于复杂和变通的解决方法。我已经发布了full code here

    最佳答案

    您的问题基本上可以归结为以下内容。这里有什么问题?

    fn book_iterator<'a>(slice: &[f64]) -> std::slice::Iter<'a, f64> {
        //                      ^^^^^^ needs to be `&'a [f64]`
        slice.iter()
    }
    
    方法book_iterator(&self)返回BookIterator<'a>'a来自哪里?它当然来自&self,因此将其注释为&'a self并编译该代码:
    use std::marker::PhantomData;
    
    // traits
    
    pub trait BookIterator<'a>: Iterator<Item = f64> {}
    
    pub trait BookSide<'a> {
        type BookIteratorType: BookIterator<'a>;
    
        // 'a added here in trait method signature
        fn book_iterator(&'a self) -> Self::BookIteratorType;
    }
    
    // implementation 1: stateful
    
    pub struct ArrayBookSide {
        quotes: Vec<f64>,
    }
    
    pub struct ArrayBookSideIterator<'a> {
        quotes_iter: std::slice::Iter<'a, f64>,
    }
    
    impl<'a> BookSide<'a> for ArrayBookSide {
        type BookIteratorType = ArrayBookSideIterator<'a>;
    
        // 'a added here below
        fn book_iterator(&'a self) -> Self::BookIteratorType {
            ArrayBookSideIterator {
                quotes_iter: self.quotes.iter(),
            }
        }
    }
    
    impl<'a> Iterator for ArrayBookSideIterator<'a> {
        type Item = f64;
    
        fn next(&mut self) -> Option<Self::Item> {
            self.quotes_iter.next().map(|&quote| quote)
        }
    }
    
    impl<'a> BookIterator<'a> for ArrayBookSideIterator<'a> {}
    
    // implementation 2: delegating
    
    pub struct CommissionBookSide<'a, B>
    where
        B: BookSide<'a>,
    {
        base_book_side: B,
        multiplier: f64,
        _marker: PhantomData<&'a B>,
    }
    
    impl<'a, B> CommissionBookSide<'a, B>
    where
        B: BookSide<'a>,
    {
        pub fn new(base_book_side: B) -> CommissionBookSide<'a, B> {
            CommissionBookSide {
                base_book_side,
                multiplier: 1.1,
                _marker: PhantomData {},
            }
        }
    }
    
    impl<'a, B> BookSide<'a> for CommissionBookSide<'a, B>
    where
        B: BookSide<'a>,
    {
        type BookIteratorType = CommissionIterator<'a, B::BookIteratorType>;
    
        // 'a added here before
        fn book_iterator(&'a self) -> Self::BookIteratorType {
            CommissionIterator {
                base_iterator: self.base_book_side.book_iterator(),
                multiplier: self.multiplier,
                _marker: PhantomData {},
            }
        }
    }
    
    pub struct CommissionIterator<'a, BI>
    where
        BI: BookIterator<'a>,
    {
        base_iterator: BI,
        multiplier: f64,
        _marker: PhantomData<&'a BI>,
    }
    
    impl<'a, BI> Iterator for CommissionIterator<'a, BI>
    where
        BI: BookIterator<'a>,
    {
        type Item = BI::Item;
    
        fn next(&mut self) -> Option<Self::Item> {
            self.base_iterator
                .next()
                .map(|quote| quote * self.multiplier)
        }
    }
    
    impl<'a, BI> BookIterator<'a> for CommissionIterator<'a, BI> where BI: BookIterator<'a> {}
    
    playground

    关于generics - 如何在Rust中实现装饰器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65864390/

    相关文章:

    c# - 泛型阻止虚函数调用?

    c# - 通用类和接口(interface)的非通用版本

    c++ - 从类中返回一个字符串——奇怪的行为

    java - getOwnerType 方法的示例

    python - python装饰器可以使函数能够智能地操作单个对象和集合对象吗?

    rust - 如何使用 serde 序列化选项?

    rust - 将大 float 转换为 int 时会发生什么?

    rust - Cargo 可以在不构建应用程序的情况下下载和构建依赖项吗?

    java - 使用 for every 迭代 HashSet

    java - 迭代 CopyOnWriteArrayList 时出现 UnsupportedOperationException