Rust: use IntoIterator inside generalized function - rust

When I do cycle as
fn main() {
let mut a = vec![1,2].into_iter().cycle();
assert_eq!(a.next().unwrap(), 1);
assert_eq!(a.next().unwrap(), 2);
assert_eq!(a.next().unwrap(), 1);
assert_eq!(a.next().unwrap(), 2);
}
it works well as I expect.
But when I try to write generalized function as
pub fn cycle_generalized_func<T>(into_iter: T) -> impl Iterator<Item = T::Item>
where
T: IntoIterator,
T::Item: Clone,
{
into_iter.into_iter().cycle()
}
And try to use as
let mut a = cycle(vec![1,2]);
id does not compline and produce errors on into_iter.into_iter().cycle() row like:
the trait bound <T as IntoIterator>::IntoIter: Clone is not satisfied
the trait Clone is not implemented for <T as IntoIterator>::IntoIterrustcE0277
iterator.rs(3270, 23): required by a bound in std::iter::Iterator::cycle
main.rs(6, 19): consider further restricting the associated type: , <T as IntoIterator>::IntoIter: Clone
What do I do wrong? I have no idea how to fix it

The type of Iterator::cycle is:
fn cycle(self) -> Cycle<Self>ⓘ
where
Self: Clone
That is, it requires the iterator itself to be : Clone, not the Item. To fix your code, replace T::Item: Clone with T::IntoIter: Clone.
This compiles for me:
pub fn cycle_generalized_func<T>(into_iter: T) -> impl Iterator<Item = T::Item>
where
T: IntoIterator,
T::IntoIter: Clone,
{
into_iter.into_iter().cycle()
}
If you need this to work with iterators that are not Clone but the items are, you'll have to collect all items into a container like Vec first:
pub fn cycle_generalized_func<T>(into_iter: T) -> impl Iterator<Item = T::Item>
where
T: IntoIterator,
T::Item: Clone,
{
into_iter
.into_iter()
.collect::<Vec<_>>()
.into_iter()
.cycle()
}

Related

How to derive Clone for structures with boxed closure?

I have the following structure:
struct MyStruct {
foo: Box<dyn Fn(usize) -> usize>
}
And I want to derive Clone for MyStruct. However, the compiler turns out error:
the trait bound `dyn std::ops::Fn(usize) -> usize: std::clone::Clone` is not satisfied
And for now (rustc 1.46.0), the dyn does not support addition of non-auto traits like Box<dyn Fn(usize) -> usize + Clone>.
From the rust-reference:
A closure is Clone or Copy if it does not capture any values by unique immutable or mutable reference, and if all values it captures by copy or move are Clone or Copy, respectively.
So I think this derivation makes sense in theory, but I don't know if I can do it for now.
I don't mind manually implementing Clone for MyStruct, but I don't know how to do it, either.
I don't want to do something like
#[derive(Clone)]
struct MyStruct<F: Fn(usize) -> usize> {
foo: F
}
because this struct is used as an associated type for an implementation of another struct for a trait, and both that struct and the trait has no generics, and I don't want to messed up with PhantomData.
Expanding on #mcarton comment above, but using the dyn-clone crate to overcome Clone not being object safe, the code is quite straightforward.
use dyn_clone::DynClone;
trait FnClone: DynClone {
fn call(&self, x: usize) -> usize;
}
impl<F> FnClone for F
where F: Fn(usize) -> usize + Clone
{
fn call(&self, x: usize) -> usize {
self(x)
}
}
struct MyStruct {
foo: Box<dyn FnClone>
}
impl Clone for MyStruct {
fn clone(&self) -> MyStruct {
MyStruct {
foo: dyn_clone::clone_box(&*self.foo),
}
}
}
fn main() {
let a = MyStruct{
foo: Box::new(|x| x + 1)
};
let b = a.clone();
println!("{} {}", a.foo.call(1), b.foo.call(2));
}
This crate also provides a macro clone_trait_object! to make the Clone derivable for the Box<dyn FnClone>, but you don't seem to want that.

How do I use a &HashSet<&T> as an IntoIterator<Item = &T>?

I have a function that takes a collection of &T (represented by IntoIterator) with the requirement that every element is unique.
fn foo<'a, 'b, T: std::fmt::Debug, I>(elements: &'b I)
where
&'b I: IntoIterator<Item = &'a T>,
T: 'a,
'b: 'a,
I would like to also write a wrapper function which can work even if the elements are not unique, by using a HashSet to remove the duplicate elements first.
I tried the following implementation:
use std::collections::HashSet;
fn wrap<'a, 'b, T: std::fmt::Debug + Eq + std::hash::Hash, J>(elements: &'b J)
where
&'b J: IntoIterator<Item = &'a T>,
T: 'a,
'b: 'a,
{
let hashset: HashSet<&T> = elements.into_iter().into_iter().collect();
foo(&hashset);
}
playground
However, the compiler doesn't seem happy with my assumption that HashSet<&T> implements IntoIterator<Item = &'a T>:
error[E0308]: mismatched types
--> src/lib.rs:10:9
|
10 | foo(&hashset);
| ^^^^^^^^ expected type parameter, found struct `std::collections::HashSet`
|
= note: expected type `&J`
found type `&std::collections::HashSet<&T>`
= help: type parameters must be constrained to match other types
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
I know I could use a HashSet<T> by cloning all the input elements, but I want to avoid unnecessary copying and memory use.
If you have a &HashSet<&T> and need an iterator of &T (not &&T) that you can process multiple times, then you can use Iterator::copied to convert the iterator's &&T to a &T:
use std::{collections::HashSet, fmt::Debug, hash::Hash, marker::PhantomData};
struct Collection<T> {
item: PhantomData<T>,
}
impl<T> Collection<T>
where
T: Debug,
{
fn foo<'a, I>(elements: I) -> Self
where
I: IntoIterator<Item = &'a T> + Clone,
T: 'a,
{
for element in elements.clone() {
println!("{:?}", element);
}
for element in elements {
println!("{:?}", element);
}
Self { item: PhantomData }
}
}
impl<T> Collection<T>
where
T: Debug + Eq + Hash,
{
fn wrap<'a, I>(elements: I) -> Self
where
I: IntoIterator<Item = &'a T>,
T: 'a,
{
let set: HashSet<_> = elements.into_iter().collect();
Self::foo(set.iter().copied())
}
}
#[derive(Debug, Hash, PartialEq, Eq)]
struct Foo(i32);
fn main() {
let v = vec![Foo(1), Foo(2), Foo(4)];
Collection::<Foo>::wrap(&v);
}
See also:
Using the same iterator multiple times in Rust
Does cloning an iterator copy the entire underlying vector?
Why does cloning my custom type result in &T instead of T?
Note that the rest of this answer made the assumption that a struct named Collection<T> was a collection of values of type T. OP has clarified that this is not true.
That's not your problem, as shown by your later examples. That can be boiled down to this:
struct Collection<T>(T);
impl<T> Collection<T> {
fn new(value: &T) -> Self {
Collection(value)
}
}
You are taking a reference to a type (&T) and trying to store it where a T is required; these are different types and will generate an error. You are using PhantomData for some reason and accepting references via the iterator, but the problem is the same.
In fact, PhantomData makes the problem harder to see as you can just make up values that don't work. For example, we never have any kind of string here but we "successfully" created the struct:
use std::marker::PhantomData;
struct Collection<T>(PhantomData<T>);
impl Collection<String> {
fn new<T>(value: &T) -> Self {
Collection(PhantomData)
}
}
Ultimately, your wrap function doesn't make sense, either:
impl<T: Eq + Hash> Collection<T> {
fn wrap<I>(elements: I) -> Self
where
I: IntoIterator<Item = T>,
This is equivalent to
impl<T: Eq + Hash> Collection<T> {
fn wrap<I>(elements: I) -> Collection<T>
where
I: IntoIterator<Item = T>,
Which says that, given an iterator of elements T, you will return a collection of those elements. However, you put them in a HashMap and iterate on a reference to it, which yields &T. Thus this function signature cannot be right.
It seems most likely that you want to accept an iterator of owned values instead:
use std::{collections::HashSet, fmt::Debug, hash::Hash};
struct Collection<T> {
item: T,
}
impl<T> Collection<T> {
fn foo<I>(elements: I) -> Self
where
I: IntoIterator<Item = T>,
for<'a> &'a I: IntoIterator<Item = &'a T>,
T: Debug,
{
for element in &elements {
println!("{:?}", element);
}
for element in &elements {
println!("{:?}", element);
}
Self {
item: elements.into_iter().next().unwrap(),
}
}
}
impl<T> Collection<T>
where
T: Eq + Hash,
{
fn wrap<I>(elements: I) -> Self
where
I: IntoIterator<Item = T>,
T: Debug,
{
let s: HashSet<_> = elements.into_iter().collect();
Self::foo(s)
}
}
#[derive(Debug, Hash, PartialEq, Eq)]
struct Foo(i32);
fn main() {
let v = vec![Foo(1), Foo(2), Foo(4)];
let c = Collection::wrap(v);
println!("{:?}", c.item)
}
Here we place a trait bound on the generic iterator type directly and a second higher-ranked trait bound on a reference to the iterator. This allows us to use a reference to the iterator as an iterator itself.
See also:
How does one generically duplicate a value in Rust?
Is there any way to return a reference to a variable created in a function?
How do I write the lifetimes for references in a type constraint when one of them is a local reference?
There were a number of orthogonal issues with my code that Shepmaster pointed out, but to solve the issue of using a HashSet<&T> as an IntoIterator<Item=&T>, I found that one way to solve it is with a wrapper struct:
struct Helper<T, D: Deref<Target = T>>(HashSet<D>);
struct HelperIter<'a, T, D: Deref<Target = T>>(std::collections::hash_set::Iter<'a, D>);
impl<'a, T, D: Deref<Target = T>> Iterator for HelperIter<'a, T, D>
where
T: 'a,
{
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|x| x.deref())
}
}
impl<'a, T, D: Deref<Target = T>> IntoIterator for &'a Helper<T, D> {
type Item = &'a T;
type IntoIter = HelperIter<'a, T, D>;
fn into_iter(self) -> Self::IntoIter {
HelperIter((&self.0).into_iter())
}
}
Which is used as follows:
struct Collection<T> {
item: PhantomData<T>,
}
impl<T: Debug> Collection<T> {
fn foo<I>(elements: I) -> Self
where
I: IntoIterator + Copy,
I::Item: Deref<Target = T>,
{
for element in elements {
println!("{:?}", *element);
}
for element in elements {
println!("{:?}", *element);
}
return Self { item: PhantomData };
}
}
impl<T: Debug + Eq + Hash> Collection<T> {
fn wrap<I>(elements: I) -> Self
where
I: IntoIterator + Copy,
I::Item: Deref<Target = T> + Eq + Hash,
{
let helper = Helper(elements.into_iter().collect());
Self::foo(&helper);
return Self { item: PhantomData };
}
}
fn main() {
let v = vec![Foo(1), Foo(2), Foo(4)];
Collection::<Foo>::wrap(&v);
}
I'm guessing that some of this may be more complicated than it needs to be, but I'm not sure how.
full playground

Wrong trait chosen based on type parameter

I have a binary trait Resolve.
pub trait Resolve<RHS = Self> {
type Output;
fn resolve(self, rhs: RHS) -> Self::Output;
}
I implemented the trait for something trivial where both arguments are taken by reference (self is &'a Foo and rhs is &'b Foo):
struct Foo;
impl <'a, 'b> Resolve<&'b Foo> for &'a Foo {
type Output = Foo;
fn resolve(self, rhs: &'b Foo) -> Self::Output {
unimplemented!()
}
}
If I now write
fn main() {
let a: &Foo = &Foo;
let b = Foo;
a.resolve(&b);
}
it will compile just fine, but if I try to implement it on my struct Signal, it will not work.
pub struct Signal<'a, T> {
ps: Vec<&'a T>,
}
impl<'a, T: Resolve<&'a T, Output = T> + 'a> Signal<'a, T> {
pub fn foo(&mut self) {
let a: &T = &self.ps[0];
let b = &self.ps[1];
a.resolve(b);
}
}
error[E0507]: cannot move out of borrowed content
--> src/main.rs:25:9
|
25 | a.resolve(b);
| ^ cannot move out of borrowed content
How do I get this example working? (playground)
The trait bound on foo only says that T implements Resolve, but you try to call .resolve() on a value of type &T.
To say, instead, that references to T must implement Resolve, you need a higher-ranked trait bound:
impl<'a, T> Signal<'a, T>
where
for<'b> &'b T: Resolve<&'a T, Output = T>,
{
pub fn foo(&mut self) { ... }
}
After thinking about this I came up with a simpler solution that does not rely on HRTB.
impl<'a, T> Signal<'a, T>
where
&'a T: Resolve<&'a T, Output = T> + 'a,
{
pub fn foo(&mut self) {
let a: &T = &self.ps[0];
let b = &self.ps[1];
a.resolve(b);
}
}
This does the same, namely describe, that &T implements Resolve, but without the need of HRTB.
You have to use the where clause for this, but apart from that this is a nice and easy solution.

Trait to store structs with different generic parameters

I need to store in the same Vec instances of the same struct, but with different generic parameters. This is the struct definition:
struct Struct<'a, T: 'a> {
items: Vec<&'a T>
}
The struct has a method returning an iterator to a type that does not depend on the generic type parameter T:
impl<'a, T: 'a> Struct<'a, T> {
fn iter(&self) -> slice::Iter<&i32> {
unimplemented!()
}
}
I need to access this method for those different structs in the vector, so I've implemented this trait:
type Iter<'a> = Iterator<Item=&'a i32>;
trait Trait {
fn iter(&self) -> Box<Iter>;
}
And I've implemented the trait for Struct:
impl<'a, T: 'a> Trait for Struct<'a, T> {
fn iter(&self) -> Box<Iter> {
Box::new(self.iter())
}
}
But the compiler complains:
<anon>:21:9: 21:30 error: type mismatch resolving `<core::slice::Iter<'_, &i32> as core::iter::Iterator>::Item == &i32`:
expected &-ptr,
found i32 [E0271]
<anon>:21 Box::new(self.iter())
^~~~~~~~~~~~~~~~~~~~~
<anon>:21:9: 21:30 help: see the detailed explanation for E0271
<anon>:21:9: 21:30 note: required for the cast to the object type `core::iter::Iterator<Item=&i32> + 'static`
<anon>:21 Box::new(self.iter())
^~~~~~~~~~~~~~~~~~~~~
I've tried different possibilities for lifetime parameters in the trait, but none of them work. How can I make this work?
Rust Playground snippet
Edit
As pointed out by #MatthieuM. one problem is that the type alias is not working properly. Here's another example demonstrating this:
use std::slice;
type Iter<'a> = Iterator<Item=&'a i32>;
struct Struct<'a> { _phantom: std::marker::PhantomData<&'a i32> }
impl<'a> Struct<'a> {
fn direct<'b>(i: &'b slice::Iter<'a, i32>) -> &'b Iterator<Item=&'a i32>
{ i }
fn aliased<'b>(i: &'b slice::Iter<'a, i32>) -> &'b Iter<'a>
{ i }
}
In this example, direct compiles, but aliased not, with the error:
<anon>:12:7: 12:8 error: the type `core::slice::Iter<'a, i32>` does not fulfill the required lifetime
<anon>:12 { i }
^
note: type must outlive the static lifetime
But they seem to be the same thing. What's happening?
Problem 1 — slice::Iter<T> has an Iterator::Item of &T, thus your reference levels are mismatched. Change your method to be
fn iter(&self) -> slice::Iter<i32>
Problem 2 — Box<SomeTrait> is equivalent to Box<SomeTrait + 'static>, but your iterator does not live for the 'static lifetime. You need to explicitly bring in a lifetime:
Box<SomeTrait + 'a>
Problem 3 — I don't understand how you can create a type alias for a trait, that seems very odd. You probably don't want it anyway. Instead, create a type alias for the whole boxed version:
type IterBox<'a> = Box<Iterator<Item=&'a i32> + 'a>;
Problem 4 — Rearrange your main so that references will live long enough and add mutability:
fn main() {
let i = 3;
let v = vec![&i];
let mut traits : Vec<Box<Trait>> = Vec::new();
traits.push(Box::new(Struct{ items: v }));
}
All together:
use std::slice;
type IterBox<'a> = Box<Iterator<Item=&'a i32> + 'a>;
trait Trait {
fn iter<'a>(&'a self) -> IterBox;
}
struct Struct<'a, T: 'a> {
items: Vec<&'a T>
}
impl<'a, T: 'a> Struct<'a, T> {
fn iter(&self) -> slice::Iter<i32> {
unimplemented!()
}
}
impl<'a, T: 'a> Trait for Struct<'a, T> {
fn iter(&self) -> IterBox {
Box::new(self.iter())
}
}
fn main() {
let i = 3;
let v = vec![&i];
let mut traits: Vec<Box<Trait>> = Vec::new();
traits.push(Box::new(Struct { items: v }));
}

Implementing Deref on a struct that owns a boxed trait

I'd like to implement Deref and DefrefMut on a struct that owns a boxed trait, e.g.:
use std::ops::{Deref, DerefMut};
trait Quack {
fn quack(&self);
}
struct QuackWrap {
value: Box<Quack>
}
impl Deref for QuackWrap {
type Target = Box<Quack>;
fn deref<'a>(&'a self) -> &'a Box<Quack> {
&self.value
}
}
impl DerefMut for QuackWrap {
fn deref_mut<'a>(&'a mut self) -> &'a mut Box<Quack> {
&mut self.value
}
}
This fails to compile with the following error:
src/main.rs:14:5: 16:6 error: method `deref` has an incompatible type for trait: expected bound lifetime parameter 'a, found concrete lifetime [E0053]
src/main.rs:14 fn deref<'a>(&'a self) -> &'a Box<Quack> {
src/main.rs:15 &self.value
src/main.rs:16 }
src/main.rs:20:5: 22:6 error: method `deref_mut` has an incompatible type for trait: expected bound lifetime parameter 'a, found concrete lifetime [E0053]
src/main.rs:20 fn deref_mut<'a>(&'a mut self) -> &'a mut Box<Quack> {
src/main.rs:21 &mut self.value
src/main.rs:22 }
If I replace Box<Quack> with Box<String> (or a similar type), it works. The problem is that Quack is a trait. But I'm not sure why that generated the error message it did. Any ideas?
My question is similar to another SO question, but not quite the same. In that question, the struct has a type parameter with the trait as a constraint. Whereas in my question, there is no type parameter.
I don't want to confuse the issues, but there's a good reason that I need Box<Quack> in my application. I.e. I can't replace Quack with a type parameter. In case you care, the reason is discussed further in another SO question.
When in doubt, add more lifetime annotations:
use std::ops::{Deref, DerefMut};
trait Quack {
fn quack(&self);
}
struct QuackWrap<'b> {
value: Box<Quack + 'b>
}
impl<'b> Deref for QuackWrap<'b>{
type Target = Box<Quack + 'b>;
fn deref<'a>(&'a self) -> &'a Box<Quack + 'b> {
&self.value
}
}
impl<'b> DerefMut for QuackWrap<'b> {
fn deref_mut<'a>(&'a mut self) -> &'a mut Box<Quack + 'b> {
&mut self.value
}
}
Based on Brian's answer and Shepmaster's explanation, I updated my code as follow. I also simplified the QuackWrap struct. (That wasn't strictly necessary, but it's arguably better style than what I was doing before.)
use std::ops::{Deref, DerefMut};
trait Quack {
fn quack(&self);
}
struct QuackWrap(Box<Quack>);
impl Deref for QuackWrap {
type Target = Box<Quack + 'static>;
fn deref<'a>(&'a self) -> &'a Box<Quack + 'static> {
let QuackWrap(ref v) = *self;
v
}
}
impl DerefMut for QuackWrap {
fn deref_mut<'a>(&'a mut self) -> &'a mut Box<Quack + 'static> {
let QuackWrap(ref mut v) = *self;
v
}
}
There may be a more concise way to destructure QuackWrap in the deref and deref_mut implementations. Some of those more obscure syntax rules elude me. But for now this is fine.

Resources