【问题标题】:How to take an IntoIterator of references and return a boxed Iterator of references to the modified values?如何获取引用的 IntoIterator 并返回对修改值的引用的装箱迭代器?
【发布时间】:2017-12-04 11:15:16
【问题描述】:

我已经掌握了 Rust 生命周期的基础知识以及如何在其中使用迭代器,但仍然难以定义一个函数,该函数接受一个可迭代的元组并返回一个也分配在堆上的可迭代元组。

(我知道“可迭代”在 Rust 中没有任何意义,但我仍然会使用它而不是 IntoInterator

use std::iter::{once, repeat};

fn foo<'a, I>(costs: I) -> Box<Iterator<Item = &'a (i32, f32)>>
where
    I: IntoIterator<Item = &'a (usize, f32)>,
{
    let preliminary_examination_costs = once(10.0).chain(repeat(20.0));
    let id_assignment_costs = once(10.0).chain(repeat(20.0));
    let batch_fixed = once(10.0).chain(repeat(0.0));
    let temp: Vec<(usize, &(i32, f32))> = costs.into_iter().enumerate().collect();
    temp.sort_by_key(|&(_, &(n, cost))| n);
    Box::new(temp.into_iter().map(|(i, &(n, cost))| {
        (
            i,
            cost + preliminary_examination_costs.next().unwrap()
                + id_assignment_costs.next().unwrap() + batch_fixed.next().unwrap(),
        )
    }))
}

(playground)

以下是错误:

error[E0277]: the trait bound `std::vec::Vec<(usize, &(i32, f32))>: std::iter::FromIterator<(usize, &'a (usize, f32))>` is not satisfied
  --> src/main.rs:10:73
   |
10 |     let temp: Vec<(usize, &(i32, f32))> = costs.into_iter().enumerate().collect();
   |                                                                         ^^^^^^^ a collection of type `std::vec::Vec<(usize, &(i32, f32))>` cannot be built from an iterator over elements of type `(usize, &'a (usize, f32))`
   |
   = help: the trait `std::iter::FromIterator<(usize, &'a (usize, f32))>` is not implemented for `std::vec::Vec<(usize, &(i32, f32))>`

error[E0271]: type mismatch resolving `<[closure@src/main.rs:12:35: 18:6 preliminary_examination_costs:_, id_assignment_costs:_, batch_fixed:_] as std::ops::FnOnce<((usize, &(i32, f32)),)>>::Output == &(i32, f32)`
  --> src/main.rs:12:5
   |
12 | /     Box::new(temp.into_iter().map(|(i, &(n, cost))| {
13 | |         (
14 | |             i,
15 | |             cost + preliminary_examination_costs.next().unwrap()
16 | |                 + id_assignment_costs.next().unwrap() + batch_fixed.next().unwrap(),
17 | |         )
18 | |     }))
   | |_______^ expected tuple, found &(i32, f32)
   |
   = note: expected type `(usize, f32)`
              found type `&(i32, f32)`
   = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::iter::Map<std::vec::IntoIter<(usize, &(i32, f32))>, [closure@src/main.rs:12:35: 18:6 preliminary_examination_costs:_, id_assignment_costs:_, batch_fixed:_]>`
   = note: required for the cast to the object type `std::iter::Iterator<Item=&(i32, f32)>`

【问题讨论】:

  • 您的代码存在的问题比您似乎提到的要多。 usize 不会隐式转换为 i32。另外,由于您在最后执行映射到新元组,返回的可迭代项不应再是绑定到 'a 生命周期的引用。
  • 从外观上看,您正在寻找类似this 的东西。但是,如果没有针对您的特定问题量身定制的调试会话,我无法找到解决您问题的方法,将其保留为 Stack Overflow 问题几乎没有什么好处。

标签: iterator rust


【解决方案1】:

遇到问题时创建MCVE 非常有用,我鼓励所有学习者都这样做。这是一个反映您的代码的此类 MCVE:

fn foo<'a, I>(costs: I) -> Box<Iterator<Item = &'a i32>>
where
    I: IntoIterator<Item = &'a i32>,
{
    Box::new(costs.into_iter().map(|i| i + 1))
}
error[E0271]: type mismatch resolving `<[closure@src/main.rs:5:36: 5:45] as std::ops::FnOnce<(&'a i32,)>>::Output == &i32`
 --> src/main.rs:5:5
  |
5 |     Box::new(costs.into_iter().map(|i| i + 1))
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected i32, found &i32
  |
  = note: expected type `i32`
             found type `&i32`
  = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::iter::Map<<I as std::iter::IntoIterator>::IntoIter, [closure@src/main.rs:5:36: 5:45]>`
  = note: required for the cast to the object type `std::iter::Iterator<Item=&i32>`

您正在接受参考,然后根据参考创建一个全新的值。这意味着返回类型不再是引用,因此您的函数签名不会得到支持。你需要改变它:

fn foo<'a, I>(costs: I) -> Box<Iterator<Item = i32>>

这将解锁另一个错误,因为编译器对 I::IntoIter 的具体类型知之甚少:

error[E0310]: the associated type `<I as std::iter::IntoIterator>::IntoIter` may not live long enough
 --> src/main.rs:6:5
  |
6 |     Box::new(costs.into_iter().map(|i| i + 1))
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = help: consider adding an explicit lifetime bound `<I as std::iter::IntoIterator>::IntoIter: 'static`...
note: ...so that the type `std::iter::Map<<I as std::iter::IntoIterator>::IntoIter, [closure@src/main.rs:6:36: 6:45]>` will meet its required lifetime bounds
 --> src/main.rs:6:5
  |
6 |     Box::new(costs.into_iter().map(|i| i + 1))
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

我们按照它的建议做并添加'static 绑定:

fn foo<'a, I>(costs: I) -> Box<Iterator<Item = i32>>
where
    I: IntoIterator<Item = &'a i32>,
    I::IntoIter: 'static,
{
    Box::new(costs.into_iter().map(|i| i + 1))
}

另见:


error[E0277]: the trait bound `std::vec::Vec<(usize, &(i32, f32))>: std::iter::FromIterator<(usize, &'a (usize, f32))>` is not satisfied

这个错误是因为你有一个(usize, &amp;'a (usize, f32)) 的迭代器,并且你试图将它们变成(usize, &amp;(i32, f32))。你不能像这样转换类型。

【讨论】:

  • 减少到 MVCE 的问题是我并不总是能以正确的方式做到这一点。例如,我稍微修改了我的foo 函数,但仍然有问题。 play.rust-lang.org/…。你能回答我的问题吗?
  • 我正在接受一对(u32, f32) 的容器。你这么说是因为我正在创造全新的价值观(这是什么意思,请准确地说)我不再返回参考资料。我想通过对 (u32, f32) 返回迭代器。据我所知,rust 可以在堆上分配对并返回对它们的引用(指针)。我不完全了解您的任何cmets,您能详细说明一下吗?我对本书第一部分的生命周期感到满意,我理解这些想法,但是当谈到通用生命周期和特征时,rust 对我来说就变得胡言乱语了。
  • 我不明白如何告诉 rust 我想要什么,也不明白它想从我这里得到什么。
  • @user1685095 我可能会写它like this
  • 感谢一些修改这工作。你能解释一下我用Box&lt;Iterator&lt;Item = (i32, f32)&gt; + 'a 告诉编译器迭代器的生命周期与生命周期a 相同吗? a 哪里是可迭代输入的项目的生命周期?
猜你喜欢
  • 1970-01-01
  • 2017-03-20
  • 1970-01-01
  • 1970-01-01
  • 2018-09-02
  • 1970-01-01
  • 1970-01-01
  • 2016-06-25
  • 2011-04-08
相关资源
最近更新 更多