I have this simple struct:
struct MyStruct {
text: String,
}
And want to implement the IntoIterator trait for it. Since Chars already implements it, I just want to wrap it:
impl IntoIterator for MyStruct {
type Item = char;
type IntoIter = std::str::Chars;
fn into_iter(self) -> Self::IntoIter {
self.text.chars().into_iter()
}
}
This results in missing lifetime specifier errors since Chars needs a lifetime specifier.
I was able to solve this by implementing my own iterator. But I wonder if it is possible just to wrap the iterator of Chars.
You can implement it for a reference to your type instead:
impl<'a> IntoIterator for &'a MyStruct {
type Item = char;
type IntoIter = std::str::Chars<'a>;
fn into_iter(self) -> Self::IntoIter {
self.text.chars()
}
}
There's no other way to achieve it without a custom OwnedChars, since IntoIter must own the String in your struct, but Chars can only hold an &str.
Related
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!
Can trait objects of type IntoIterator be boxed and held inside of a structure? I've a situation where I'd like to store a vector of objects that can be turned into iterators. My attempt at this was the code
struct Foo {
foo: Vec<Box<dyn IntoIterator<Item = usize>>>,
}
fn main() {
let _ = Foo {
foo: vec![Box::new(1..2), Box::new(vec![2,4,4])],
};
}
However, this does not compile and produces the error:
error[E0191]: the value of the associated type `IntoIter` (from trait `IntoIterator`) must be specified
--> src/main.rs:6:22
|
6 | foo: Vec<Box<dyn IntoIterator<Item = usize>>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: specify the associated type: `IntoIterator<Item = usize, IntoIter = Type>`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0191`.
I am aware that most of the time when we want to use IntoIterator we instead pass a generic into the structure. However, in this case, the items that I'd like to store do not have the same time. As such, is there a way to store a heterogenous collection of objects that can all be turned into an iterator of the same type?
What you're wanting to do doesn't make a lot of sense to me. But it would be easy to box each Iterator instead of each IntoIterator.
struct Foo {
foo: Vec<Box<dyn Iterator<Item = usize>>>,
}
fn main() {
let _ = Foo {
foo: vec![Box::new((1..2).into_iter()), Box::new(vec![2,4,4].into_iter())],
};
}
The problem you're running into is that IntoIterator is defined like this:
pub trait IntoIterator {
type Item;
type IntoIter: Iterator<Item = Self::Item>;
fn into_iter(self) -> Self::IntoIter;
}
In order for the compiler to emit monomorphic code, you have to specify both the Item type and the IntoIter type in the dyn specifier in the declaration of the foo field. But different types that implement IntoIterator have differing IntoIter types.
If it's really important to you to box up IntoIterator objects before they are actually turned into Iterators, then you have to add a new wrapper that transforms all the diverse IntoIter types into a Box<dyn Iterator>. Like this:
use std::iter::IntoIterator;
struct GenericIntoIterator<I: IntoIterator>(I);
impl<I: 'static + IntoIterator> std::iter::IntoIterator for GenericIntoIterator<I>
{
type Item = <I as IntoIterator>::Item;
type IntoIter = Box<dyn 'static + Iterator<Item = Self::Item>>;
fn into_iter(self) -> Self::IntoIter {
Box::new(self.0.into_iter())
}
}
struct Foo {
foo: Vec<Box<dyn 'static + IntoIterator<Item = usize, IntoIter = Box<dyn 'static + Iterator<Item=usize>>>>>,
}
fn main() {
let _ = Foo {
foo: vec![Box::new(GenericIntoIterator(1..2)), Box::new(GenericIntoIterator(vec![2,4,4]))],
};
}
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.
I have this trait and simple structure:
use std::path::{Path, PathBuf};
trait Foo {
type Item: AsRef<Path>;
type Iter: Iterator<Item = Self::Item>;
fn get(&self) -> Self::Iter;
}
struct Bar {
v: Vec<PathBuf>,
}
I would like to implement the Foo trait for Bar:
impl Foo for Bar {
type Item = PathBuf;
type Iter = std::slice::Iter<PathBuf>;
fn get(&self) -> Self::Iter {
self.v.iter()
}
}
However I'm getting this error:
error[E0106]: missing lifetime specifier
--> src/main.rs:16:17
|
16 | type Iter = std::slice::Iter<PathBuf>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected lifetime parameter
I found no way to specify lifetimes inside that associated type. In particular I want to express that the iterator cannot outlive the self lifetime.
How do I have to modify the Foo trait, or the Bar trait implementation, to make this work?
Rust playground
There are a two solutions to your problem. Let's start with the simplest one:
Add a lifetime to your trait
trait Foo<'a> {
type Item: AsRef<Path>;
type Iter: Iterator<Item = Self::Item>;
fn get(&'a self) -> Self::Iter;
}
This requires you to annotate the lifetime everywhere you use the trait. When you implement the trait, you need to do a generic implementation:
impl<'a> Foo<'a> for Bar {
type Item = &'a PathBuf;
type Iter = std::slice::Iter<'a, PathBuf>;
fn get(&'a self) -> Self::Iter {
self.v.iter()
}
}
When you require the trait for a generic argument, you also need to make sure that any references to your trait object have the same lifetime:
fn fooget<'a, T: Foo<'a>>(foo: &'a T) {}
Implement the trait for a reference to your type
Instead of implementing the trait for your type, implement it for a reference to your type. The trait never needs to know anything about lifetimes this way.
The trait function then must take its argument by value. In your case you will implement the trait for a reference:
trait Foo {
type Item: AsRef<Path>;
type Iter: Iterator<Item = Self::Item>;
fn get(self) -> Self::Iter;
}
impl<'a> Foo for &'a Bar {
type Item = &'a PathBuf;
type Iter = std::slice::Iter<'a, PathBuf>;
fn get(self) -> Self::Iter {
self.v.iter()
}
}
Your fooget function now simply becomes
fn fooget<T: Foo>(foo: T) {}
The problem with this is that the fooget function doesn't know T is in reality a &Bar. When you call the get function, you are actually moving out of the foo variable. You don't move out of the object, you just move the reference. If your fooget function tries to call get twice, the function won't compile.
If you want your fooget function to only accept arguments where the Foo trait is implemented for references, you need to explicitly state this bound:
fn fooget_twice<'a, T>(foo: &'a T)
where
&'a T: Foo,
{}
The where clause makes sure that you only call this function for references where Foo was implemented for the reference instead of the type. It may also be implemented for both.
Technically, the compiler could automatically infer the lifetime in fooget_twice so you could write it as
fn fooget_twice<T>(foo: &T)
where
&T: Foo,
{}
but it's not smart enough yet.
For more complicated cases, you can use a Rust feature which is not yet implemented: Generic Associated Types (GATs). Work for that is being tracked in issue 44265.
Use a wrapper type
If the trait and all its implementations are defined in one crate, a helper type can be useful:
trait Foo {
fn get<'a>(&'a self) -> IterableFoo<'a, Self> {
IterableFoo(self)
}
}
struct IterableFoo<'a, T: ?Sized + Foo>(pub &'a T);
For a concrete type that implements Foo, implement the iterator conversion on the IterableFoo wrapping it:
impl Foo for Bar {}
impl<'a> IntoIterator for IterableFoo<'a, Bar> {
type Item = &'a PathBuf;
type IntoIter = std::slice::Iter<'a, PathBuf>;
fn into_iter(self) -> Self::IntoIter {
self.0.v.iter()
}
}
This solution does not allow implementations in a different crate. Another disadvantage is that an IntoIterator bound cannot be encoded into the definition of the trait, so it will need to be specified as an additional (and higher-rank) bound for generic code that wants to iterate over the result of Foo::get:
fn use_foo_get<T>(foo: &T)
where
T: Foo,
for<'a> IterableFoo<'a, T>: IntoIterator,
for<'a> <IterableFoo<'a, T> as IntoIterator>::Item: AsRef<Path>
{
for p in foo.get() {
println!("{}", p.as_ref().to_string_lossy());
}
}
Associated type for an internal object providing desired functionality
The trait can define an associated type that gives access to a part of the object that, bound in a reference, provides the necessary access traits.
trait Foo {
type Iterable: ?Sized;
fn get(&self) -> &Self::Iterable;
}
This requires that any implementation type contains a part that can be so exposed:
impl Foo for Bar {
type Iterable = [PathBuf];
fn get(&self) -> &Self::Iterable {
&self.v
}
}
Put bounds on the reference to the associated type in generic code that uses the the result of get:
fn use_foo_get<'a, T>(foo: &'a T)
where
T: Foo,
&'a T::Iterable: IntoIterator,
<&'a T::Iterable as IntoIterator>::Item: AsRef<Path>
{
for p in foo.get() {
println!("{}", p.as_ref().to_string_lossy());
}
}
This solution permits implementations outside of the trait definition crate.
The bound work at generic use sites is as annoying as with the previous solution.
An implementing type may need an internal shell struct with the only purpose of providing the associated type, in case when the use-site bounds are not as readily satisfied as with Vec and IntoIterator in the example discussed.
In future, you'll want an associated type constructor for your lifetime 'a but Rust does not support that yet. See RFC 1598
In theory, Dynamically-Sized Types (DST) have landed and we should now be able to use dynamically sized type instances. Practically speaking, I can neither make it work, nor understand the tests around it.
Everything seems to revolve around the Sized? keyword... but how exactly do you use it?
I can put some types together:
// Note that this code example predates Rust 1.0
// and is no longer syntactically valid
trait Foo for Sized? {
fn foo(&self) -> u32;
}
struct Bar;
struct Bar2;
impl Foo for Bar { fn foo(&self) -> u32 { return 9u32; }}
impl Foo for Bar2 { fn foo(&self) -> u32 { return 10u32; }}
struct HasFoo<Sized? X> {
pub f:X
}
...but how do I create an instance of HasFoo, which is DST, to have either a Bar or Bar2?
Attempting to do so always seems to result in:
<anon>:28:17: 30:4 error: trying to initialise a dynamically sized struct
<anon>:28 let has_foo = &HasFoo {
I understand broadly speaking that you can't have a bare dynamically sized type; you can only interface with one through a pointer, but I can't figure out how to do that.
Disclaimer: these are just the results of a few experiments I did, combined with reading Niko Matsakis's blog.
DSTs are types where the size is not necessarily known at compile time.
Before DSTs
A slice like [i32] or a bare trait like IntoIterator were not valid object types because they do not have a known size.
A struct could look like this:
// [i32; 2] is a fixed-sized vector with 2 i32 elements
struct Foo {
f: [i32; 2],
}
or like this:
// & is basically a pointer.
// The compiler always knows the size of a
// pointer on a specific architecture, so whatever
// size the [i32] has, its address (the pointer) is
// a statically-sized type too
struct Foo2<'a> {
f: &'a [i32],
}
but not like this:
// f is (statically) unsized, so Foo is unsized too
struct Foo {
f: [i32],
}
This was true for enums and tuples too.
With DSTs
You can declare a struct (or enum or tuple) like Foo above, containing an unsized type. A type containing an unsized type will be unsized too.
While defining Foo was easy, creating an instance of Foo is still hard and subject to change. Since you can't technically create an unsized type by definition, you have to create a sized counterpart of Foo. For example, Foo { f: [1, 2, 3] }, a Foo<[i32; 3]>, which has a statically known size and code some plumbing to let the compiler know how it can coerce this into its statically unsized counterpart Foo<[i32]>. The way to do this in safe and stable Rust is still being worked on as of Rust 1.5 (here is the RFC for DST coercions for more info).
Luckily, defining a new DST is not something you will be likely to do, unless you are creating a new type of smart pointer (like Rc), which should be a rare enough occurrence.
Imagine Rc is defined like our Foo above. Since it has all the plumbing to do the coercion from sized to unsized, it can be used to do this:
use std::rc::Rc;
trait Foo {
fn foo(&self) {
println!("foo")
}
}
struct Bar;
impl Foo for Bar {}
fn main() {
let data: Rc<Foo> = Rc::new(Bar);
// we're creating a statically typed version of Bar
// and coercing it (the :Rc<Foo> on the left-end side)
// to as unsized bare trait counterpart.
// Rc<Foo> is a trait object, so it has no statically
// known size
data.foo();
}
playground example
?Sized bound
Since you're unlikely to create a new DST, what are DSTs useful for in your everyday Rust coding? Most frequently, they let you write generic code that works both on sized types and on their existing unsized counterparts. Most often these will be Vec/[] slices or String/str.
The way you express this is through the ?Sized "bound". ?Sized is in some ways the opposite of a bound; it actually says that T can be either sized or unsized, so it widens the possible types we can use, instead of restricting them the way bounds typically do.
Contrived example time! Let's say that we have a FooSized struct that just wraps a reference and a simple Print trait that we want to implement for it.
struct FooSized<'a, T>(&'a T)
where
T: 'a;
trait Print {
fn print(&self);
}
We want to define a blanket impl for all the wrapped T's that implement Display.
impl<'a, T> Print for FooSized<'a, T>
where
T: 'a + fmt::Display,
{
fn print(&self) {
println!("{}", self.0)
}
}
Let's try to make it work:
// Does not compile. "hello" is a &'static str, so self print is str
// (which is not sized)
let h_s = FooSized("hello");
h_s.print();
// to make it work we need a &&str or a &String
let s = "hello"; // &'static str
let h_s = &s; // & &str
h_s.print(); // now self is a &str
Eh... this is awkward... Luckily we have a way to generalize the struct to work directly with str (and unsized types in general): ?Sized
//same as before, only added the ?Sized bound
struct Foo<'a, T: ?Sized>(&'a T)
where
T: 'a;
impl<'a, T: ?Sized> Print for Foo<'a, T>
where
T: 'a + fmt::Display,
{
fn print(&self) {
println!("{}", self.0)
}
}
now this works:
let h = Foo("hello");
h.print();
playground
For a less contrived (but simple) actual example, you can look at the Borrow trait in the standard library.
Back to your question
trait Foo for ?Sized {
fn foo(&self) -> i32;
}
the for ?Sized syntax is now obsolete. It used to refer to the type of Self, declaring that `Foo can be implemented by an unsized type, but this is now the default. Any trait can now be implemented for an unsized type, i.e. you can now have:
trait Foo {
fn foo(&self) -> i32;
}
//[i32] is unsized, but the compiler does not complain for this impl
impl Foo for [i32] {
fn foo(&self) -> i32 {
5
}
}
If you don't want your trait to be implementable for unsized types, you can use the Sized bound:
// now the impl Foo for [i32] is illegal
trait Foo: Sized {
fn foo(&self) -> i32;
}
To amend the example that Paolo Falabella has given, here is a different way of looking at it with the use of a property.
struct Foo<'a, T>
where
T: 'a + ?Sized,
{
printable_object: &'a T,
}
impl<'a, T> Print for Foo<'a, T>
where
T: 'a + ?Sized + fmt::Display,
{
fn print(&self) {
println!("{}", self.printable_object);
}
}
fn main() {
let h = Foo {
printable_object: "hello",
};
h.print();
}
At the moment, to create a HasFoo storing a type-erased Foo you need to first create one with a fixed concrete type and then coerce a pointer to it to the DST form, that is
let has_too: &HasFoo<Foo> = &HasFoo { f: Bar };
Calling has_foo.f.foo() then does what you expect.
In future these DST casts will almost certainly be possible with as, but for the moment coercion via an explicit type hint is required.
Here is a complete example based on huon's answer. The important trick is to make the type that you want to contain the DST a generic type where the generic need not be sized (via ?Sized). You can then construct a concrete value using Bar1 or Bar2 and then immediately convert it.
struct HasFoo<F: ?Sized = dyn Foo>(F);
impl HasFoo<dyn Foo> {
fn use_it(&self) {
println!("{}", self.0.foo())
}
}
fn main() {
// Could likewise use `&HasFoo` or `Rc<HasFoo>`, etc.
let ex1: Box<HasFoo> = Box::new(HasFoo(Bar1));
let ex2: Box<HasFoo> = Box::new(HasFoo(Bar2));
ex1.use_it();
ex2.use_it();
}
trait Foo {
fn foo(&self) -> u32;
}
struct Bar1;
impl Foo for Bar1 {
fn foo(&self) -> u32 {
9
}
}
struct Bar2;
impl Foo for Bar2 {
fn foo(&self) -> u32 {
10
}
}