I am new to rust and was going over iterators and this where I got blocked.So if I am implementing Iterator directly and not IntoIterator,how come I am able to call into_iter
(and too multiple times).My understanding is if I implemented IntoIterator,I should be going to Iterator via into_iter.But if I am able to implement Iterator,why do I still need into_iter(would be called implicitly if i didnt give I guess for for in )
struct StrSplit<'a> {
rest: &'a str,
delim: &'a str,
}
impl<'a> StrSplit<'a> {
fn new(haystack: &'a str, delim: &'a str) -> Self {
Self {
rest: haystack,
delim,
}
}
}
impl<'a> Iterator for StrSplit<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<Self::Item> {
let to_return;
if let Some(next) = self.rest.find(self.delim) {
to_return = &self.rest[..next];
self.rest = &self.rest[next + self.delim.len() + 1..];
return Some(to_return);
} else if !self.rest.is_empty() {
to_return = self.rest;
self.rest="";
return Some(to_return);
}
return None;
}
}
fn main() {
let check = StrSplit::new("this was to check what was to be checked", "was");
let iterr = check.into_iter().into_iter().into_iter();
for part in iterr {
println!("{}", part);
}
}
If you're new to Rust this might be a bit subtle, but it's a thing that you'll see quite often with the traits of the standard library:
You correctly note that into_iter is a method of the IntoIterator trait. You also note that you implemented Iterator for your struct, but not IntoIterator. So what gives?
Checking the methods defined on Iterator, there's no into_iter to be found.
But now if you check the documentation for IntoIterator, and scroll down to the list of Implementors https://doc.rust-lang.org/std/iter/trait.IntoIterator.html#implementors
you will find the following snippet:
impl<I> IntoIterator for I
where
I: Iterator
This is called a blanket implementation: For any type T that implements the Iterator trait, there will be automatically an implementation for the IntoIterator trait!
Because your struct implements Iterator, it also gets IntoIterator implemented.
There's some other examples of this in the standard library. For example, if you implement From<A> for some type B, you automatically get the Into<B> trait implemented for type A.
Another example is ToString:
impl<T> ToString for T where
T: Display + ?Sized,
Any type that implements the Display trait gets the ToString trait for free!
Related
I am building a custom data structure which supposes to return an iterator for its elements. If simplified, it can look like this:
use std::iter::{Iterator, StepBy};
// My collection which returns iterator to it's elements
pub trait MyCollection<'a, T: 'a> {
type I: Iterator<Item = &'a T>;
fn find_something(&'a self) -> Self::I;
}
Now, in some cases, I would like to create a "wrapper" for this collection that transforms the elements returned by the iterator. For the sake of this example let's assume that this wrapper allows skipping over some elements of the original iterator:
// Wrapper for a collection that allows iterating over elements with a step
pub struct StepWrapper<'a, A>(&'a A, usize);
impl<'a, T: 'a, A: MyCollection<'a, T>> MyCollection<'a, T> for StepWrapper<'a, A> {
type I = StepBy<A::I>;
fn find_something(&'a self) -> Self::I {
self.0.find_something().step_by(self.1)
}
}
// Function which takes a collection and a step value and returns a wrapped collection
fn wrap<'a, T: 'a, A: MyCollection<'a, T>>(a: &'a A, step: usize) -> impl MyCollection<'a, T> {
StepWrapper(a, step)
}
Unfortunately, I get a compilation error when trying to use this code:
// Example
impl<'a> MyCollection<'a, u64> for Vec<u64> {
type I = std::slice::Iter<'a, u64>;
fn find_something(&'a self) -> Self::I {
return self.iter();
}
}
fn main() {
let collection = vec![12, 13, 14];
let wrapped = wrap(&collection, 2);
// Error now
let result = wrapped.find_something().skip(1).next();
// ^^^^^^^ borrowed value does not live long enough
println!("{}", result.unwrap());
}
I understand that StepWrapper<'a, A>::find_something requires self to be borrowed for the same lifetime as the original collection. But all my attempts to decouple lifetimes of a collection and a wrapper were unuseful. Essentially a find_something function in the wrapper needs to return a result which outlives itself. Is there a way to express it in Rust?
The pattern you're using is called a streaming iterator, and unfortunately it's not possible with the Iterator trait.
This is a current weakness of Rust's type system: it lacks what are known as generic associated types, or GATs. There's an RFC for this language feature and a tracking issue.
In the meantime, the streaming_iterator crate is designed to provide the functionality you're looking for.
I was trying to use take(n) on an iterator to do something with the first n items, but then do something different (a for ... in ... loop) with the remaining items.
In the declaration:
fn take(self, n: usize) -> Take<Self>
the self as first argument tells me that take() must be used on an owned value, not a reference (&self) or mutable reference (&mut self).
The documentation for by_ref() says it returns a mutable reference, and
This is useful to allow applying iterator adaptors while still
retaining ownership of the original iterator.
It includes an example using by_ref().take(n), and then continuing to use the iterator (just like I wanted).
My question is, why am I allowed to call take() on a mutable reference (as opposed to requiring an owned value)? In other words, shouldn't take() have been declared something like:
fn take(&mut self, n: usize) -> Take<Self>
to make it possible to use it with a mutable reference?
What declaration should I have been looking for that would have told me this was possible?
Rust treats T, &T, and &mut T as separate types. Being separate types we can implement different methods for each of them. Example:
struct Struct;
trait Printable {
fn print(self);
}
impl Printable for Struct {
fn print(self) {
println!("I'm an owned Struct");
}
}
impl Printable for &Struct {
fn print(self) {
println!("I'm a Struct reference");
}
}
fn main() {
let s = Struct;
let s_ref = &Struct;
s.print();
s_ref.print();
}
If we desugar the trait method we get:
fn print(self: Self) { /* implementation */ }
Where Self is equal to the implementing type, which in the case of Struct is:
fn print(self: Struct) { /* implementation */ }
And in the case of &Struct is:
fn print(self: &Struct) { /* implementation */ }
So really self can be an owned type or an immutable reference or a mutable reference. The reason why you can call take on mutable references to Iterators is because of this generic blanket impl which implements the Iterator trait on all mutable references to Iterators:
impl<'_, I> Iterator for &'_ mut I where I: Iterator + ?Sized { /* implementation */ }
Let's use vec.into_iter() as a concrete example. Since it returns std::vec::IntoIter which implements Iterator we know this implementation of take must exist:
take(self: std::vec::IntoIter, n: usize) -> Take<std::vec::IntoIter> { /* implementation */ }
However, we also know that an implementation of take for &mut std::vec::IntoIter must exist because it would be automatically generated by the generic blanket impl mentioned above, and that implementation's signature would look like this:
take(self: &mut std::vec::IntoIter, n: usize) -> Take<&mut std::vec::IntoIter> { /* implementation */ }
And this why you can call take on any mutable reference to any type that implements Iterator.
LimitedFifoQueue is a struct that wraps the functionality of a VecDeque to limit the number of items it will store at any time:
use std::collections::{vec_deque, VecDeque};
use std::fmt;
use std;
#[derive(Debug)]
pub struct LimitedFifoQueue<T> {
size: usize,
store: VecDeque<T>,
}
impl<T> LimitedFifoQueue<T> where T: fmt::Display {
pub fn new(size: usize) -> LimitedFifoQueue<T> {
LimitedFifoQueue {
size: size,
store: VecDeque::with_capacity(size),
}
}
pub fn push(&mut self, elem: T) {
self.store.push_front(elem);
if self.store.len() > self.size {
self.store.pop_back();
}
}
pub fn clear(&mut self) {
self.store.clear();
}
}
I've implemented the IntoIterator trait as follows:
impl<T> IntoIterator for LimitedFifoQueue<T> where T: fmt::Display {
type Item = T;
type IntoIter = vec_deque::IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
self.store.into_iter()
}
}
And a simplified function that loops through and prints each Item:
fn print_all<I>(lines: &I) where I: IntoIterator {
for string in lines.into_iter() {
println!("{}", string);
}
}
This gives me the following error:
println!("{}", string);
^^^^^^ the trait `std::fmt::Display` is not implemented for `<I as std::iter::IntoIterator>::Item`
I have created a playground of the code with a full stack trace here.
Also, I'm aware that there may be a better way to accomplish what I'm trying to do. I'd love to hear any additional suggestions.
How can I implement std::fmt::Display for a custom IntoIterator::Item?
You cannot. Item might be a type you don't own, and Display is a trait you don't own. You cannot implement a trait you don't own for a type you don't own.
All you can do is require that Item implements Display:
fn print_all<I>(lines: I)
where I: IntoIterator,
I::Item: fmt::Display,
{
for string in lines.into_iter() {
println!("{}", string);
}
}
You don't need any of the other T: Display bounds on your data structure or its methods, as none of those implementations care to print out a value.
Incidentally, into_iter is automatically called on the for-loops argument, so you only need to say:
fn print_all<I>(lines: I)
where I: IntoIterator,
I::Item: fmt::Display,
{
for string in lines {
println!("{}", string);
}
}
You may also wish to review How to implement Iterator and IntoIterator for a simple struct?, as you are passing &lfq into print_all, but &LimitedFifoQueue doesn't implement IntoIterator, only LimitedFifoQueue does. These are different types. You'll need something like
impl<'a, T> IntoIterator for &'a LimitedFifoQueue<T> {
type Item = &'a T;
type IntoIter = vec_deque::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.store.iter()
}
}
This problem has nothing to do with your IntoIterator implementation or the rest of your type definition. Just take a look at this code:
fn print_all<I>(lines: &I) where I: IntoIterator {
for string in lines.into_iter() {
println!("{}", string);
}
}
This piece of code doesn't even know about your LimitedFifoQueue type! It takes a value of generic type I. What do we know about I? It implements IntoIterator. Great, what does that tell us about the values the iterator will spit out? Nothing!
So it could be anything, in particular also stuff that doesn't implement fmt::Display. So what we want to do is to annotate that the items of the iterator should at least implement fmt::Display. How is that done? By adding a bound to the associated type Item of the IntoIterator trait:
fn print_all<I>(lines: &I)
where I: IntoIterator,
I::Item: fmt::Display,
{ ... }
Once you understand that you can also add bounds to associated items this makes intuitive sense.
After you fixed that error, another error will be reported, about "moving out of borrowed content". This is a fairly standard error, which I won't explain in detail here. But in summary: your print_all() function should receive a I instead of a &I.
Why does the following code work when Cloned expects a DoubleEndedIterator<Item=&'a T> but iter() returns an Iterator<T> (instead of an Iterator<&T> as it expects)?
use std::clone::Clone;
use std::iter::{Rev, Cloned};
use std::fmt::Debug;
fn reversed<'a, U, T>(iter: U) -> Rev<Cloned<U>>
where U: DoubleEndedIterator<Item=&'a T>,
T: 'a + Clone + Debug
{
iter.cloned().rev()
}
fn main() {
let v0 = (0..10).collect::<Vec<u32>>();
let mut v0r = v0.clone();
v0r.reverse();
assert_eq!(v0r, reversed(v0.iter()).collect::<Vec<_>>());
}
T is generic parameter, and it has a scope in which it applies. Specifically, the T parameter for std::slice::Iter is different from the T declared on reversed. If this were not the case, I think that it would basically be impossible for humans to ever use generics. It would be like if every variable called name referred to the same thing!
but iter() returns an Iterator<T>
This isn't true; you can't currently return a trait. You can only return a type that implements a trait. Additionally, std::slice::Iter<T> implements Iterator by returning references to T:
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T
}
I am defining a trait that takes in a i: &I parameter. I would like to use this i value in a for loop.
For example:
struct Test;
trait Bar<I> {
fn bar(&self, i: &I);
}
impl<T, I: IntoIterator<Item=T>> Bar<I> for Test {
fn bar(&self, i: &I) {
for x in i {
println!("woo!");
}
}
}
fn main() {
let vec = vec!(1, 2, 3);
let test = Test;
test.bar(&vec);
}
Playground link
This results in the error:
<anon>:10:9: 12:10 error: the trait `core::iter::Iterator` is not implemented for the type `&I` [E0277] <anon>:10 for x in i { <anon>:11 println!("woo!"); <anon>:12 } <anon>:10:9: 12:10 help: see the detailed explanation for E0277 <anon>:10:9: 12:10 note: `&I` is not an iterator; maybe try calling `.iter()` or a similar method <anon>:10:9: 12:10 note: required by `core::iter::IntoIterator::into_iter` error: aborting due to previous error playpen: application terminated with error code 101
I was playing around with using the Deref trait to see if I could get something to work, but to no avail.
I would really like to keep the immutable reference in the function definition as this trait is attempting to be generic over many types, and defining the other implementations using Bar<&'a I> has lead to some other lifetime related issues that I have been having trouble with as well.
Saying that I is an IntoIterator doesn't say anything about &I, e.g. x..y is an IntoIterator (because it is an Iterator and all of them are), but &(x..y) is not.
You specifically want to bound &I, which fortunately can be done via a where clause, e.g.
impl<I, T> Bar<I> for Test
where for<'a> &'a I: IntoIterator<Item = T>
{
fn bar(&self, i: &I) {
for x in i {
println!("woo!");
}
}
}
The for<'a> just means "for any lifetime 'a", and so the where clause is saying that &I is always an IntoIterator (just writing where &I: IntoIterator isn't quite enough).
There's some choices to be made about the T parameter there, e.g.
IntoIterator<Item = T>
IntoIterator<Item = &'a T>
remove the parameter entirely and just write IntoIterator
The best choice will depend on exactly what you're doing with it. For the specific example in the question, I would go with 3, since the Item type doesn't matter at all. Number 2 makes sense because almost all types that have &T implement IntoIterator will yield references (it also seems to avoids most of the bugs/general difficulties the compiler currently has about reasoning about universal quantification over lifetimes, which hit 1 and 3).
In Rust, by convention, methods whose name starts with into take their argument by value and transform it into another value, usually reusing some resources from the original value. The IntoIterator trait and its into_iter follow that convention.
Are you sure you need to use &I in your trait? Your codes works just fine with I. That's because there is an implementation of IntoIterator for &Vec<T>. That's why one can write for x in &v where v is a Vec.
struct Test;
trait Bar<I> {
fn bar(&self, i: I);
}
impl<T, I: IntoIterator<Item=T>> Bar<I> for Test {
fn bar(&self, i: I) {
for x in i {
println!("woo!");
}
}
}
fn main() {
let vec = vec!(1, 2, 3);
let test = Test;
test.bar(&vec);
}
playground