-4

I've grasped the basics of Rust lifetimes and how to work with iterators in it, but still have troubles to define a function that takes an iterable of tuples and return an iterable of tuples also allocated on the heap.

(I know that "iterable" doesn't mean anything in Rust but I will still use it instead of 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)

Here's the errors:

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)>`
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
user1685095
  • 5,787
  • 9
  • 51
  • 100
  • 1
    Your code has more issues than the one that you seem to mention. `usize` is not implicitly converted to `i32`. Plus, since you're performing a map into new tuples at the end, the items of the returned iterable should no longer be references bound to the `'a` lifetime. – E_net4 Dec 04 '17 at 11:31
  • By the looks of it, you're looking for something like [this](https://play.rust-lang.org/?gist=f20ffa67c1bc814279b53d0dce351545&version=stable). However, I can't find a way to address your question without a debugging session tailored to your particular problem, with little benefit to be kept as a Stack Overflow question. – E_net4 Dec 04 '17 at 12:02

1 Answers1

3

It's very useful to create a MCVE when encountering a problem, and it's something I encourage all learners to undertake. Here's one such MCVE that mirrors your code:

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>`

You are accepting a reference then creating a brand new value based on the reference. That means that the return type is no longer a reference, thus your function signature is not upheld. You need to change it:

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

This will unlock another error because the compiler doesn't know enough about the concrete type of 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))
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

We do as it suggests and add the 'static bound:

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))
}

See also:


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

This error is because you have an iterator of (usize, &'a (usize, f32)) and you are trying to make them into (usize, &(i32, f32)). You can't convert types like this.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • The problem with reducing to MVCE is that I'm not always can do that in the right way. For example I've modified my `foo` function somewhat, but still have problems. https://play.rust-lang.org/?gist=b2bef2a57f76aae6c70eb0e28f4db44f&version=stable. Can you instead answer my question. – user1685095 Dec 04 '17 at 15:58
  • I'm accepting a container of pairs `(u32, f32)`. You're saying that because I'm creating brand new values (what does it mean, be precise, please) I'm not returning references any more. I want to return iterator over pairs `(u32, f32)`. For all I know rust can allocate pairs on the heap and return references (pointers) to them. I don't understand any of your comments completely, can you elaborate more? I feel comfortable with lifetimes from the first part of the book, I understand the ideas, but when it comes to generic lifetimes and traits rust becomes gibberish to me. – user1685095 Dec 04 '17 at 16:03
  • I don't understand how to tell rust what I want and I don't understand what it wants from me. – user1685095 Dec 04 '17 at 16:03
  • @user1685095 I'd probably write it [like this](https://play.rust-lang.org/?gist=3b2f574f8e3db6889dc67d35048d95b6&version=stable). – Shepmaster Dec 04 '17 at 16:20
  • Thanks with a bit of modifications this works. Can you explain what do I tell to the compiler with `Box + 'a` That the life time of iterator is the same as lifetime `a`? Where `a` is a lifetime of items from input iterable? – user1685095 Dec 04 '17 at 18:53
  • @user1685095 You have to state `Iterator + 'a` inside `Box` because the iterator only works while the original source of items exists. This source, which is the reference to the vector of tuples, is bound to the lifetime `'a`. Therefore, the box cannot outlive `'a`. – E_net4 Dec 04 '17 at 20:23
  • @E_net4 what is ` + 'a` means? – user1685095 Dec 04 '17 at 21:09
  • @user1685095 Time for you to hit [the book](https://doc.rust-lang.org/book/second-edition/ch19-02-advanced-lifetimes.html). ;) – E_net4 Dec 04 '17 at 21:13
  • @E_net4 I've already read it not so long ago, but haven't had opportunity to implement much in rust, so I forgot some parts. What chapter should I look? – user1685095 Dec 05 '17 at 08:07