最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

rust - Clone a collection in reverse order - Stack Overflow

programmeradmin0浏览0评论

How to clone a collection in reverse manner. I tried using DoubleEndedIterator to iterate backwards to clone each element of the collection.

fn clone_backward<List, ItemType>(list: &List) -> List
where
    for<'a> &'a List: IntoIterator<Item = &'a ItemType>,
    for<'a> <&'a List as IntoIterator>::IntoIter: DoubleEndedIterator,
    for<'a> &'a List::IntoIter: DoubleEndedIterator<Item = &'a ItemType>,
    List: FromIterator<ItemType> + IntoIterator,
    ItemType: Clone,
{
    list.into_iter()
    .rev()
    .cloned()
    .collect()
}

fn main() {
    let first_list = vec![1, 2, 3, 4, 5];
    let second_list: Vec<i32> = clone_backward(&first_list);
        
    assert_eq!(vec![5, 4, 3, 2, 1], second_list);
}

Error

error[E0277]: the trait bound `for<'a> <&'a _ as IntoIterator>::IntoIter: DoubleEndedIterator` is not satisfied
  --> src/main.rs:17:48
   |
17 |     let second_list: Vec<i32> = clone_backward(&first_list);
   |                                 -------------- ^^^^^^^^^^^ the trait `for<'a> DoubleEndedIterator` is not implemented for `<&'a _ as IntoIterator>::IntoIter`
   |                                 |
   |                                 required by a bound introduced by this call
   |
note: this is a known limitation of the trait solver that will be lifted in the future
  --> src/main.rs:17:48
   |
17 |     let second_list: Vec<i32> = clone_backward(&first_list);
   |                                 ---------------^^^^^^^^^^^-
   |                                 |              |
   |                                 |              the trait solver is unable to infer the generic types that should be inferred from this argument
   |                                 add turbofish arguments to this call to specify the types manually, even if it's redundant
note: required by a bound in `clone_backward`
  --> src/main.rs:4:51
   |
1  | fn clone_backward<List, ItemType>(list: &List) -> List
   |    -------------- required by a bound in this function
...
4  |     for<'a> <&'a List as IntoIterator>::IntoIter: DoubleEndedIterator,
   |                                                   ^^^^^^^^^^^^^^^^^^^ required by this bound in `clone_backward`

error[E0277]: the trait bound `for<'a> &'a _: DoubleEndedIterator` is not satisfied
  --> src/main.rs:17:48
   |
17 |     let second_list: Vec<i32> = clone_backward(&first_list);
   |                                 -------------- ^^^^^^^^^^^ the trait `for<'a> DoubleEndedIterator` is not implemented for `&'a _`
   |                                 |
   |                                 required by a bound introduced by this call
   |
note: required by a bound in `clone_backward`
  --> src/main.rs:5:33
   |
1  | fn clone_backward<List, ItemType>(list: &List) -> List
   |    -------------- required by a bound in this function
...
5  |     for<'a> &'a List::IntoIter: DoubleEndedIterator<Item = &'a ItemType>,
   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `clone_backward`
help: consider removing the leading `&`-reference
   |
17 -     let second_list: Vec<i32> = clone_backward(&first_list);
17 +     let second_list: Vec<i32> = clone_backward(first_list);
   |

For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` (bin "playground") due to 2 previous errors

How to clone a collection in reverse manner. I tried using DoubleEndedIterator to iterate backwards to clone each element of the collection.

fn clone_backward<List, ItemType>(list: &List) -> List
where
    for<'a> &'a List: IntoIterator<Item = &'a ItemType>,
    for<'a> <&'a List as IntoIterator>::IntoIter: DoubleEndedIterator,
    for<'a> &'a List::IntoIter: DoubleEndedIterator<Item = &'a ItemType>,
    List: FromIterator<ItemType> + IntoIterator,
    ItemType: Clone,
{
    list.into_iter()
    .rev()
    .cloned()
    .collect()
}

fn main() {
    let first_list = vec![1, 2, 3, 4, 5];
    let second_list: Vec<i32> = clone_backward(&first_list);
        
    assert_eq!(vec![5, 4, 3, 2, 1], second_list);
}

Error

error[E0277]: the trait bound `for<'a> <&'a _ as IntoIterator>::IntoIter: DoubleEndedIterator` is not satisfied
  --> src/main.rs:17:48
   |
17 |     let second_list: Vec<i32> = clone_backward(&first_list);
   |                                 -------------- ^^^^^^^^^^^ the trait `for<'a> DoubleEndedIterator` is not implemented for `<&'a _ as IntoIterator>::IntoIter`
   |                                 |
   |                                 required by a bound introduced by this call
   |
note: this is a known limitation of the trait solver that will be lifted in the future
  --> src/main.rs:17:48
   |
17 |     let second_list: Vec<i32> = clone_backward(&first_list);
   |                                 ---------------^^^^^^^^^^^-
   |                                 |              |
   |                                 |              the trait solver is unable to infer the generic types that should be inferred from this argument
   |                                 add turbofish arguments to this call to specify the types manually, even if it's redundant
note: required by a bound in `clone_backward`
  --> src/main.rs:4:51
   |
1  | fn clone_backward<List, ItemType>(list: &List) -> List
   |    -------------- required by a bound in this function
...
4  |     for<'a> <&'a List as IntoIterator>::IntoIter: DoubleEndedIterator,
   |                                                   ^^^^^^^^^^^^^^^^^^^ required by this bound in `clone_backward`

error[E0277]: the trait bound `for<'a> &'a _: DoubleEndedIterator` is not satisfied
  --> src/main.rs:17:48
   |
17 |     let second_list: Vec<i32> = clone_backward(&first_list);
   |                                 -------------- ^^^^^^^^^^^ the trait `for<'a> DoubleEndedIterator` is not implemented for `&'a _`
   |                                 |
   |                                 required by a bound introduced by this call
   |
note: required by a bound in `clone_backward`
  --> src/main.rs:5:33
   |
1  | fn clone_backward<List, ItemType>(list: &List) -> List
   |    -------------- required by a bound in this function
...
5  |     for<'a> &'a List::IntoIter: DoubleEndedIterator<Item = &'a ItemType>,
   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `clone_backward`
help: consider removing the leading `&`-reference
   |
17 -     let second_list: Vec<i32> = clone_backward(&first_list);
17 +     let second_list: Vec<i32> = clone_backward(first_list);
   |

For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` (bin "playground") due to 2 previous errors
Share Improve this question edited Feb 2 at 10:38 cafce25 27.6k5 gold badges45 silver badges57 bronze badges asked Feb 2 at 9:31 HarryHarry 3,1421 gold badge24 silver badges46 bronze badges 4
  • 1 Please read the error message, it tells you how to fix this: add turbofish arguments to this call to specify the types manually, even if it's redundant – cafce25 Commented Feb 2 at 9:51
  • 1 If you write let second_list: Vec<i32> = clone_backward::<Vec<i32>, i32>(&first_list); in your main, it works. It seems this is a known limitation of the trait solver. – Finomnis Commented Feb 2 at 9:59
  • 1 @Harry It still fails because you have overly restrictive annotations in there that aren't actually required. – Finomnis Commented Feb 2 at 10:08
  • But again, do not use these types of functions repeatedly in a row. Use chained iterators instead; they are way more efficient. But if you implement those for learning purposes, go ahead. – Finomnis Commented Feb 2 at 10:11
Add a comment  | 

2 Answers 2

Reset to default 1

It seems that at the time of writing, the trait solver is unable to resolve this kind if indirection.

It seems that it is required to annotate the types manually, like so:

fn clone_backward<List, ItemType>(list: &List) -> List
where
    for<'a> &'a List: IntoIterator<Item = &'a ItemType>,
    for<'a> <&'a List as IntoIterator>::IntoIter: DoubleEndedIterator,
    List: FromIterator<ItemType>,
    ItemType: Clone,
{
    list.into_iter().rev().cloned().collect()
}

fn main() {
    let first_list = vec![1, 2, 3, 4, 5];
    let second_list: Vec<i32> = clone_backward::<Vec<i32>, _>(&first_list);

    assert_eq!(vec![5, 4, 3, 2, 1], second_list);
}

(Note there were a couple of unnecessary annotations I removed)

You can optimize this one step further so you only need to annotate the return type, as (through a little bit of annotation pain) the element of the vector can be determined by the compiler:

fn clone_backward<List>(list: &List) -> List
where
    for<'a> &'a List: IntoIterator,
    for<'a> <&'a List as IntoIterator>::IntoIter: DoubleEndedIterator,
    for<'a> <&'a List as IntoIterator>::Item: std::ops::Deref,
    for<'a> <<&'a List as IntoIterator>::Item as std::ops::Deref>::Target: Clone,
    for<'a> List: FromIterator<<<&'a List as IntoIterator>::Item as std::ops::Deref>::Target>,
{
    list.into_iter().rev().map(|val| (*val).clone()).collect()
}

fn main() {
    let first_list = vec![1, 2, 3, 4, 5];
    let second_list: Vec<i32> = clone_backward::<Vec<i32>>(&first_list);

    assert_eq!(vec![5, 4, 3, 2, 1], second_list);
}

But I think, at the time of writing, this is as good as it will get.

Personally I don't fully know your exact use case (the question is very vague on any specific use case) but the issue can easily be solved by just using those same 4 lines of code wherever needed, as for me personally, I would be more confused than anything to have it be pulled into a dedicated fn. It's a variation on a somewhat common and very recognizable pattern, .iter().{cloned/map/filter/flatten}.collect().

As the error message shows, the issue stems from a temporary limitation in the compiler that hopefully should be patched soon. The compiler isn't able to handle the generics, specifically the trait bounds on IntoIterator::IntoIter when ref's are involved.

Other options would be to de-genericize the fn; have it take a specific data type and thus bypass the limitation (specifically thinking if you need to pass this fn specifically as a callback) or you can have the fn user create and provide the DEI itself directly, passing in basically clone_backward(first_list.iter().rev()) although that would lean in even further into the function being a less readable, non-chainable, otherwise extremely straightforward now 2-liner.

发布评论

评论列表(0)

  1. 暂无评论