I am trying to write a trait which requires an inner type Iter. And Iter should implements Iterator. I am getting such error "overflow evaluating the requirement <str as SomeTrait>::Iter == _" and can't understand what it wants. Can anybody help to understand ?)
pub trait SomeIter {
type Iter where Self::Iter: Iterator;
}
struct NumberIter(u32, u8);
impl Iterator for NumberIter {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
if self.1 == 32 || (self.0 >> self.1) == 0 {
None
} else {
let ret = ((self.0 >> self.1) as u8) & 0xFF;
self.1 += 8;
Some(ret)
}
}
}
impl SomeTrait for str {
type Iter = NumberIter;
}
The compiler advised reading some examples in https://doc.rust-lang.org/error-index.html#E0275 but there weren't similar ones.
The problem is the resolution over the where Self::Iter part (because it is recursive), where you just really need to constrain the type:
pub trait SomeIter {
type Iter: Iterator;
}
Playground
Related
I would like to return a reference to an owned object that is in a collection (viz., a Vec), but I cannot seem to get the lifetimes correct. Here is what I first tried:
struct StringHolder {
strings: Vec<String>,
i: usize,
}
impl Iterator for StringHolder {
type Item<'a> = &'a String;
fn next(&mut self) -> Option<Self::Item> {
if self.i >= self.strings.len() {
None
} else {
self.i += 1;
Some(&self.strings[self.i])
}
}
}
fn main() {
let sh = StringHolder { strings: vec![], i: 0 };
for string in sh {
println!("{}", string);
}
}
I get an error that generic associated types are unstable and lifetimes do not match type in trait. I tried a few other iterations, but nothing seemed to work.
I gather that this may not be possible based on some things I've read, but then I can't seem to figure out how Vec does it itself. For example, I can use the following to simply iterate over the underlying Vec and return a reference on each iteration:
struct StringHolder {
strings: Vec<String>,
}
impl<'a> IntoIterator for &'a StringHolder {
type Item = &'a String;
type IntoIter = ::std::slice::Iter<'a, String>;
fn into_iter(self) -> Self::IntoIter {
(&self.strings).into_iter()
}
}
fn main() {
let sh = StringHolder { strings: vec!["A".to_owned(), "B".to_owned()] };
for string in &sh {
println!("{}", string);
}
}
So that makes me think it is possible, I just haven't figured out lifetimes yet. Thanks for your help.
The Iterator trait doesn't included a lifetime for Item, which is one of the errors you are seeing. The other alludes to GATs which is an unstable Rust feature. GATs applied to this example would let you bound the lifetime of an item for each individual call to next() instead of all items having the same lifetime. Having said that, the Iterator trait is unlikely to change so this more flexible behaviour would have to be a new trait.
Given the design of the Iterator trait, you can't have an iterator own its data and have its Item be a reference to it. There just isn't a way to express the lifetime.
The way iterators are usually written, in order to have the items be references, is to make them hold a reference to the underlying data. This provides a named lifetime for the data, which can be used on the associated Item. Vec sort of does this, but it's a bit different because Vec actually gets its iteration from slice.
Your complete example:
struct StringHolder {
strings: Vec<String>,
}
struct StringHolderIter<'a> {
string_holder: &'a StringHolder,
i: usize,
}
impl<'a> Iterator for StringHolderIter<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<Self::Item> {
if self.i >= self.string_holder.strings.len() {
None
} else {
self.i += 1;
Some(&self.string_holder.strings[self.i - 1])
}
}
}
impl<'a> IntoIterator for &'a StringHolder {
type Item = &'a str;
type IntoIter = StringHolderIter<'a>;
fn into_iter(self) -> Self::IntoIter {
StringHolderIter {
string_holder: self,
i: 0,
}
}
}
Code:
use std::collections::HashSet;
use std::{mem, ptr, fmt};
use std::ops::Deref;
enum Unsafety {
Normal
}
enum ImplPolarity { Positive }
struct TraitRef;
struct Ty;
struct ImplItem;
enum ItemKind {
Impl(Unsafety,
ImplPolarity,
Option<TraitRef>, // (optional) trait this impl implements
Box<Ty>, // self
),
}
struct Item {
node: ItemKind,
}
pub struct P<T: ?Sized> {
ptr: Box<T>
}
impl<T: 'static> P<T> {
pub fn unwrap(self) -> T {
*self.ptr
}
}
impl<T: ?Sized> Deref for P<T> {
type Target = T;
fn deref(&self) -> &T {
&self.ptr
}
}
fn main() {
let mut items = Vec::<P<Item>>::new();
let mut item2: Item;
for item in items.drain(..) {
if let ItemKind::Impl(Unsafety::Normal,
ImplPolarity::Positive,
Some(ref trait_type),
ref for_type) = item.node {
} else {
// item2 = *item; // AAA
item2 = item.unwrap(); // BBB
}
}
}
Produce the compile-time error:
error[E0505]: cannot move out of `item` because it is borrowed
--> /home/xxx/.emacs.d/rust-playground/at-2017-07-29-204629/snippet.rs:64:21
|
61 | ref for_type) = item.node {
| ---- borrow of `item` occurs here
...
64 | item2 = item.unwrap();
I do not understand two things:
Why does it complain about the borrow in the if branch while we in else branch? They are supposed to be mutually exclusive, and a borrow in one should not influence another.
If I replace Vec in let mut items = Vec::<P<Item>>::new(); with Vec<Box<Item>> and uncomment line AAA and comment line BBB, then it compiles. Both Box and P implement Deref, so the item.node expression should be the same.
Here's a much clearer example:
struct Item;
struct P<T> {
ptr: Box<T>,
}
impl<T> P<T> {
fn new(v: T) -> Self {
P { ptr: Box::new(v) }
}
}
impl<T> std::ops::Deref for P<T> {
type Target = T;
fn deref(&self) -> &T {
&self.ptr
}
}
fn main() {
let mut item = P::new(Item);
// let mut item = Box::new(Item);
*item;
}
Both Box and P implement Deref, so the item.node expression should be the same.
Hard truth time: moving out of Box is special-cased in the compiler. It does not use Deref. Moving out of a Box deallocates the memory and gives you ownership. It is not possible to implement this special ability ourselves.
Maybe at some point in the future a hypothetical trait like DerefMove will be added. This trait is hard to get right. There have been a number of attempts for an RFC for it, but none are currently open.
See also:
Dereferencing Box<T> gives back value instead of reference
How can I reuse a box that I have moved the value out of?
I'm trying to understand why Rayon's filter() function won't work without needing to specify the right type, whereas filter() will work correctly if I'm not using a parallel iterator. Here's my code:
use rayon::prelude::*;
fn is_even(n: i64) -> bool {
n % 2 == 0
}
fn main() {
let v: Vec<_> = (1..300_000_000)
.into_par_iter() // works correctly without this line, but not parallel
.filter(|&x| is_even(x))
.collect();
}
And here are the error messages:
error[E0271]: type mismatch resolving `<rayon::range::Iter<i32> as rayon::iter::ParallelIterator>::Item == i64`
--> src/main.rs:11:10
|
11 | .filter(|&x| is_even(x))
| ^^^^^^ expected `i32`, found `i64`
error[E0271]: type mismatch resolving `<rayon::range::Iter<i32> as rayon::iter::ParallelIterator>::Item == i64`
--> src/main.rs:12:10
|
12 | .collect();
| ^^^^^^^ expected `i32`, found `i64`
|
= note: required because of the requirements on the impl of `rayon::iter::ParallelIterator` for `rayon::iter::Filter<rayon::range::Iter<i32>, [closure#src/main.rs:11:17: 11:32]>`
Why does filter() only work without specifying the kind of integer if I'm not using into_par_iter()? (I know I can fix it by labeling the range as i64, but not why it would be necessary)
Update: This type inference issue has been fixed in rayon 1.5.1
Why indeed... Digging into it, this is due to the way rayon determines if a Range implements IntoParallelIterator.
impl<T> IntoParallelIterator for Range<T> where Iter<T>: ParallelIterator { ... }
struct Iter<T> {
range: Range<T>,
}
impl ParallelIterator for Iter<u8> { type Item = u8; }
impl ParallelIterator for Iter<u16> { type Item = u16; }
impl ParallelIterator for Iter<u32> { type Item = u32; }
impl ParallelIterator for Iter<u64> { type Item = u64; }
impl ParallelIterator for Iter<i8> { type Item = i8; }
impl ParallelIterator for Iter<i16> { type Item = i16; }
impl ParallelIterator for Iter<i32> { type Item = i32; }
impl ParallelIterator for Iter<i64> { type Item = i64; }
// etc
The compiler is trying to see if (1..300_000_000).into_par_iter() is even legal and because ParallelIterator is implemented for the Iter<T> types separately, its forced to deduce now what T is before it proceeds.
See the non-working reconstruction on the playground.
If instead they did something like:
impl<T> ParallelIterator for Iter<T> where T: SomeIntegerType + Send {
type Item = T;
}
trait SomeIntegerType {}
impl SomeIntegerType for u8 {}
impl SomeIntegerType for u16 {}
impl SomeIntegerType for u32 {}
impl SomeIntegerType for u64 {}
impl SomeIntegerType for i8 {}
impl SomeIntegerType for i16 {}
impl SomeIntegerType for i32 {}
impl SomeIntegerType for i64 {}
// etc
The compiler can see that Iter does implement ParallelIterator as long as T implements SomeIntegerType, but it doesn't have to deduce the type now, it can wait until later.
See my working reconstruction on the playground.
In Rust, is it possible to generalize a trait to always implement another trait, or to have a struct "inherit" its traits' implementations of other traits?
For instance, in the following code, I don't want to have to implement equality between every possible type of Length. If I implement it on the trait, how do I use it on the structs that implement that trait?
// `Length` Trait, which includes a standardized unit
trait Length {
fn _standardized(&self) -> f64;
}
impl std::cmp::PartialEq for dyn Length {
fn eq(&self, other: &Self) -> bool {
self._standardized() == other._standardized()
}
}
// `Centimeters`
struct Centimeters(f64);
impl Length for Centimeters {
fn _standardized(&self) -> f64 {
let &Centimeters(cm) = self;
cm
}
}
// `Inches`
struct Inches(i32);
impl Length for Inches {
fn _standardized(&self) -> f64 {
let &Inches(inches) = self;
inches as f64 * 2.54
}
}
fn main() {
let foot = Inches(12);
let meter = Centimeters(100.0);
let cmp = if foot == meter { "equal" } else { "not equal" };
println!("One foot is {} to one meter.", cmp);
}
Currently, that throws an error:
binary operation `==` cannot be applied to type `partial_ord::Centimeters`
note: an implementation of `std::cmp::PartialEq` might be missing for `partial_ord::Centimeters`
rustc(E0369)
Based on this question, I also tried:
impl<T> std::cmp::PartialEq for T where T: Length {
which gives
conflicting implementations of trait `std::cmp::PartialEq<&_>` for type `&_`:
Is there a way to do what I'm trying to do? If so, what is it?
(And, if you're looking for extra kudos, what gap in my Rust paradigm does this example highlight?)
I'm trying to re-implement Vec::retain() with print statements so that I can figure out how it works, but I'm stuck on this extended type annotation where F: FnMut(&T) -> bool. I understand why it's there, but I can't figure out how to annotate it in the trait declaration so it stops throwing errors (and lets me fix the other ones in the code):
trait TestVec {
fn retain_with_prints<F>(&mut self, mut f: F);
}
impl<T> TestVec for Vec<T> {
fn retain_with_prints<F>(&mut self, mut f: F)
where F: FnMut(&T) -> bool
{
let len = self.len();
let mut del = 0;
{
let v = &mut **self;
for i in 0..len {
println!("on position: {}", &i);
if !f(&v[i]) {
del += 1;
println!("incremented del to: {}", del);
} else if del > 0 {
println!("swapping {} for {}", v[i - del], v[i]);
v.swap(i - del, i);
}
}
}
if del > 0 {
println!("removing last {} elements of vector", del);
self.truncate(len - del);
}
}
}
fn main() {
let v = vec![0,1,2,3,4,5];
v.retain_with_prints(|item| { item % 2 == 0 });
}
Errors:
As is: error: the requirement `for<'r> F: std::ops::FnMut<(&'r T,)>` appears on the impl method but not on the corresponding trait method [E0276]
Adding where clause to trait: error: type name `T` is undefined or not in scope [E0412]
The compiler doesn't seem to like it if I try to specify trait<T> either, and I can't seem to get the right thing to come up in search results.
How do I specify this?
You need to parameterize the trait:
trait TestVec<T> {
fn retain_with_prints<F>(&mut self, mut f: F)
where F: FnMut(&T) -> bool;
}
And also link the types at implementation time.
impl<T> TestVec<T> for Vec<T>
Beyond that, you will need to require that your T implements Display and make your variable mutable:
impl<T> TestVec<T> for Vec<T>
where T: std::fmt::Display
{
let mut v = vec![0,1,2,3,4,5];