Rust reference object-safety confused me for a while, and says:
Explicitly non-dispatchable functions require:
Have a where Self: Sized bound (receiver type of Self (i.e. self) implies this).
But I found code::iter::Iterator has dozen of methods are declared as explicitly non-dispatchable functions, one of them below:
pub trait Iterator {
...
fn count(self) -> usize
where
Self: Sized,
{
self.fold(
0,
#[rustc_inherit_overflow_checks]
|count, _| count + 1,
)
}
...
}
However, all of them are dispatchable by trait-object at rust-playground:
fn main() {
let it: &mut dyn Iterator<Item = u32> = &mut [1, 2, 3].into_iter();
assert_eq!(3, it.count()); // ok
}
That is good, I start try to implements a worked example, but it can not be dispatched at rust-playground, and report compiler error: "the dispatch method cannot be invoked on a trait object" that is expected:
fn main() {
pub trait Sup {
fn dispatch(self) -> String
where
Self: Sized,
{
"sup".to_string()
}
}
struct Sub;
impl Sup for Sub {
fn dispatch(self) -> String {
"sub".to_string()
}
}
let it: &mut dyn Sup = &mut Sub;
assert_eq!("trait", it.dispatch());
}
Why explicitly non-dispatchable methods in code::iter::Iterator are dispatchable? Is there any magic which I didn't found?
The reason is simple, if we think of this: what type we're invoking the method count on?
Is it dyn Iterator<Item = u32>? Let's check:
assert_eq!(3, <dyn Iterator<Item = u32>>::count(it));
Nope, there are two errors:
error[E0308]: mismatched types
--> src/main.rs:3:53
|
3 | assert_eq!(3, <dyn Iterator<Item = u32>>::count(it));
| ^^ expected trait object `dyn Iterator`, found mutable reference
|
= note: expected trait object `dyn Iterator<Item = u32>`
found mutable reference `&mut dyn Iterator<Item = u32>`
error[E0277]: the size for values of type `dyn Iterator<Item = u32>` cannot be known at compilation time
--> src/main.rs:3:53
|
3 | assert_eq!(3, <dyn Iterator<Item = u32>>::count(it));
| --------------------------------- ^^ doesn't have a size known at compile-time
| |
| required by a bound introduced by this call
|
= help: the trait `Sized` is not implemented for `dyn Iterator<Item = u32>`
note: required by a bound in `count`
OK, well... is it &mut dyn Iterator, then?
assert_eq!(3, <&mut dyn Iterator<Item = u32>>::count(it));
Now it compiles. It's understandable that the second error goes away - &mut T is always Sized. But why do the &mut dyn Iterator has access to the method of Iterator?
The answer is in the documentation. First, dyn Iterator obviously implements Iterator - that's true for any trait. Second, there's implementation of Iterator for any &mut I, where I: Iterator + ?Sized - which our dyn Iterator satisfies.
Now, one may ask - what code is executed when we use this implementation? After all, count requires consuming self, so calling it on reference can't delegate to the dyn Iterator - otherwise we'd be back to square one, dispatching non-dispatchable.
Here, the answer lies in the structure of the Iterator trait. As one can see, it has only a single required method, namely next, which takes &mut self; all other methods are provided, that is, they have some default implementations using next - for example, here's it for count:
fn count(self) -> usize
where
Self: Sized,
{
self.fold(
0,
#[rustc_inherit_overflow_checks]
|count, _| count + 1,
)
}
where fold, in turn, is the following:
fn fold<B, F>(mut self, init: B, mut f: F) -> B
where
Self: Sized,
F: FnMut(B, Self::Item) -> B,
{
let mut accum = init;
while let Some(x) = self.next() {
accum = f(accum, x);
}
accum
}
As you can see, knowing just the next, compiler can derive fold and then count.
Now, back to our &mut dyn Iterators. Let's check how, exactly, this implementation looks like; it appears to be quite simple:
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator + ?Sized> Iterator for &mut I {
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
(**self).next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
(**self).size_hint()
}
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
(**self).advance_by(n)
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
(**self).nth(n)
}
}
You can see that the &self and &mut self methods, i.e. the ones which can be called on the trait object, are forwarded by the reference to the inner value and dispatched dynamically.
The self methods, i.e. the ones which cannot use the trait object, are dispached statically using their default implementation, which consume the reference and pass it, eventually, into one of these - non-consuming, dynamically-dispatched - methods.
Related
For a type
pub struct Child<'a> {
buf: &'a mut [u8],
}
I can define a trait and implement the trait for the type but with a lifetime that is bound to a calling function's context (not to a local loop context):
pub trait MakeMut<'a> {
fn make_mut(buf: &'a mut [u8]) -> Self;
}
impl<'a> MakeMut<'a> for Child<'a> {
fn make_mut(buf: &'a mut [u8]) -> Self {
Self { buf }
}
}
And first to show a somewhat working example because x is only borrowed within the context of the loop because Child::make_mut is hardcoded in the map1 function:
pub fn map1<F>(mut func: F)
where
F: FnMut(&mut Child),
{
let mut vec = vec![0; 16];
let x = &mut vec;
for i in 0..2 {
let offset = i * 8;
let s = &mut x[offset..];
let mut w = Child::make_mut(s);
func(&mut w);
}
}
But in trying to make map2, a generic version of map1 where the T is bound to the MakeMut trait but with lifetime of the entire function body, this won't compile, for good reasons (the T lifetimes that would be created by T: MakeMut<'a> have the lifetime of map2, not the inner loop):
pub fn map2<'a, F, T>(mut func: F) // lifetime `'a` defined here
where
T: MakeMut<'a>,
F: FnMut(&mut T),
{
let mut vec = vec![0; 16];
let x = &mut vec;
for i in 0..2 {
let offset = i * 8;
let s = &mut x[offset..];
let mut w = T::make_mut(s); // error: argument requires that `*x` is borrowed for `'a`
func(&mut w);
}
}
I want to do something almost like this but of course it doesn't compile either:
pub trait MakeMut {
fn make_mut<'a>(buf: &'a mut [u8]) -> Self;
}
impl<'a> MakeMut for Child<'a> {
fn make_mut(buf: &'a mut [u8]) -> Self { // lifetime mismatch
Self{ buf }
}
}
with the compiler errors:
error[E0308]: method not compatible with trait
--> src/main.rs:45:5
|
45 | fn make_mut(buf: &'a mut [u8]) -> Self {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected fn pointer `fn(&'a mut [u8]) -> Child<'_>`
found fn pointer `fn(&'a mut [u8]) -> Child<'_>`
note: the lifetime `'a` as defined here...
--> src/main.rs:45:5
|
45 | fn make_mut(buf: &'a mut [u8]) -> Self {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime `'a` as defined here
--> src/main.rs:44:6
|
44 | impl<'a> MakeMut for Child<'a> {
| ^^
Is there a syntax that allows a trait for a Child<'a> where the 'a is defined by the input argument to the method make_mut? So a generic function could be defined for a trait that returns an instance but where the instance lifetime is not the entire function, but just a shorter lifetime defined by an inner block?
I understand the lifetime is part of the type being returned, but it almost seems like a higher-ranked trait bound (HRTB) would suite this problem except I haven't found a way to specify the lifetime that suites the trait and the method signatures.
Here is a playground link https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=fb28d6da9d89fde645edeb1ca0ae5b21
Your first attempt is close to what you want. For reference:
pub trait MakeMut<'a> {
fn make_mut(buf: &'a mut [u8]) -> Self;
}
impl<'a> MakeMut<'a> for Child<'a> {
fn make_mut(buf: &'a mut [u8]) -> Self {
Self { buf }
}
}
The first problem is the bound on T in map2:
pub fn map2<'a, F, T>(mut func: F)
where
T: MakeMut<'a>,
F: FnMut(&mut T),
This requires the compiler to deduce a single 'a that applies for the whole function. Since lifetime parameters come from outside of the function, the lifetime 'a is necessarily longer than the function invocation, which means anything with lifetime 'a has to outlive the function. Working backwards from the T::make_mut() call, the compiler eventually deduces that x is &'a mut Vec<_> which means vec has to outlive the function invocation, but there's no possible way it can since it's a local.
This can be fixed by using a higher-rank trait bound indicating that T has to implement MakeMut<'a> for any possible lifetime 'a, which is expressed like this:
pub fn map2<F, T>(mut func: F)
where
T: for<'a> MakeMut<'a>,
F: FnMut(&mut T),
With this change, the code compiles.
What you'll then find is that you can't ever actually call map2 with T=Child<'_> because you'll run into the same problem in a different place. The caller must specify a specific lifetime for 'a in Child<'a>, but this disagrees with the HRTB -- you have impl<'a> MakeMut<'a> for Child<'a> but the HRTB wants impl<'a, 'b> MakeMut<'b> for Child<'a>, and that brings back the lifetime problem in that implementation's make_mut.
One way around this is to decouple the implementation of MakeMut from Child, providing a "factory type" that uses associated types. This way, the caller doesn't have to supply any pesky lifetime argument that could cause trouble later.
pub trait MakeMut<'a> {
type Item;
fn make_mut(buf: &'a mut [u8]) -> Self::Item;
}
struct ChildFactory;
impl<'a> MakeMut<'a> for ChildFactory {
type Item = Child<'a>;
fn make_mut(buf: &'a mut [u8]) -> Child<'a> {
Child { buf }
}
}
Then we modify map2 to be aware of the associated type:
pub fn map2<F, T>(mut func: F)
where
T: for<'a> MakeMut<'a>,
F: for<'a, 'b> FnMut(&'b mut <T as MakeMut<'a>>::Item),
whew
Now, finally, we can use map2:
map2::<_, ChildFactory>(|v| {});
(Playground)
I am seeking help to understand why the borrow checker fails for the following minimal non-working example, and I would be very happy to learn how to correctly implement what I was trying to do:
use std::collections::HashSet;
struct Foo {
data: HashSet<usize>
}
impl Foo {
fn test<'a, F, T>(&mut self, _operation: F) -> ()
where F: Fn(&'a HashSet<usize>, &'a HashSet<usize>) -> T,
T: Iterator<Item=&'a usize>
{
let update: HashSet<usize> = vec![4, 2, 9].into_iter().collect();
self.data = _operation(&self.data, &update).copied().collect();
}
fn new() -> Self {
Foo { data: HashSet::new() }
}
}
fn main() {
let mut foo: Foo = Foo::new();
foo.test(HashSet::intersection);
}
My main source of confusion is that, if I replace the call to _operation with HashSet::intersection, the code compiles. I thought that the type of the parameter _operation would allow me to pass both HashSet::intersection and HashSet::union as operations here.
For the record, this is the error I receive:
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> src\main.rs:13:32
|
13 | self.data = _operation(&self.data, &update).copied().collect();
| ^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined on the method body at 8:23...
--> src\main.rs:8:23
|
8 | fn test<'a, F, T>(&mut self, _operation: F) -> ()
| ^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src\main.rs:13:32
|
13 | self.data = _operation(&self.data, &update).copied().collect();
| ^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the method body at 8:13...
--> src\main.rs:8:13
|
8 | fn test<'a, F, T>(&mut self, _operation: F) -> ()
| ^^
note: ...so that reference does not outlive borrowed content
--> src\main.rs:13:32
|
13 | self.data = _operation(&self.data, &update).copied().collect();
| ^^^^^^^^^^
For more information about this error, try `rustc --explain E0495`.
error: could not compile `aoc06` due to previous error
The issue, as the (albeit cryptic) compiler message suggests, is that there is a lifetime mismatch: _operation expects HashSet references that live as long as 'a, but &self.data has a lifetime 'b, the elided lifetime of &mut self, and &update has a different lifetime that lasts the duration of the test function body.
To resolve this issue, we must specify that the function type F takes in HashMap references of arbitrary lifetimes, not just the specific lifetime 'a -- this lets the compiler infer the appropriate lifetime when _operation is invoked. This is why we need Higher-Rank Trait Bounds (HRTBs):
fn test<F, T>(&mut self, _operation: F) -> ()
where F: for<'a> Fn(&'a HashSet<usize>, &'a HashSet<usize>) -> T,
However, this raises another issue. How do we apply the higher-ranked lifetime 'a to the type parameter T? Unfortunately Rust does not support higher-kinded types, but we can get away with "abstracting" out the the function type F and the higher-kinded type T to a trait and an associated type on said trait.
trait Operation<'a, T: 'a> {
type Output: Iterator<Item = &'a T>;
fn operate(self, a: &'a HashSet<T>, b: &'a HashSet<T>) -> Self::Output;
}
The Operation trait represents an operation on two HashSets that returns an iterator over references, equivalent to the functions HashSet::union, HashSet::intersection, and the like. We can achieve this using the following impl, which ensures that HashSet::intersection and the like implement Operation:
impl<'a, T: 'a, I, F> Operation<'a, T> for F
where
I: Iterator<Item = &'a T>,
F: FnOnce(&'a HashSet<T>, &'a HashSet<T>) -> I,
{
type Output = I;
fn operate(self, a: &'a HashSet<T>, b: &'a HashSet<T>) -> Self::Output {
self(a, b)
}
}
We can then use a HRTB on the Operation trait instead, which does not require any nested higher-kinded types:
fn test(&mut self, _operation: impl for<'a> Operation<'a, usize>) -> () {
let update: HashSet<usize> = vec![4, 2, 9].into_iter().collect();
self.data = _operation.operate(&self.data, &update).copied().collect();
println!("{:?}", self.data);
}
Playground
The arguments you are passing do not match the lifetime which you declared the Fn bound with.
fn test<'a, F, T>(&mut self, _operation: F) -> ()
'a is some arbitrary lifetime that may be specified by the caller,
F: Fn(&'a HashSet<usize>, &'a HashSet<usize>) -> T,
which must be adequate for the references given to _operation,
let update: HashSet<usize> = vec![4, 2, 9].into_iter().collect();
self.data = _operation(&self.data, &update).copied().collect();
but here you pass in a borrow from self (whose lifetime is not specified to outlive 'a) and a borrow from update (which is a local variable, which cannot outlive 'a).
In order to correctly write this, you need to specify that _operation may be called with any lifetime (which thus includes the lifetimes of borrows of local variables). That's simple, by itself:
fn test<F, T>(&mut self, _operation: F) -> ()
where
F: for<'a> Fn(&'a HashSet<usize>, &'a HashSet<usize>) -> T,
Note that 'a is no longer a lifetime parameter of test. Instead it's part of the bound on F: you can read this for<'a> notation as “for any lifetime, which we will call 'a, F may be called as a function with references &'a ...”.
However, this isn't actually a solution, because you also have T: Iterator<Item = &'a usize>, which uses 'a again. It isn't currently possible to write a where clause that expresses this relationship, particularly as even without the item being a reference, the iterator will be borrowing the &'a HashSets.
This is an unfortunate limitation of current Rust — it also comes up in trying to write a function that takes an async function which borrows an input (which is structurally the same as your situation, with Future in place of Iterator). However, there is a workaround: you can define a trait for the function, which has a single lifetime parameter that links everything together. (This doesn't impose any extra work on the caller of your function, because the trait is blanket implemented for all suitable functions.)
Here's your code with such a trait added and the needed modifications to fn test():
use std::collections::HashSet;
trait IteratorCallback<'a> {
type Output: Iterator<Item = &'a usize> + 'a;
fn call(self, a: &'a HashSet<usize>, b: &'a HashSet<usize>) -> Self::Output;
}
impl<'a, F, T> IteratorCallback<'a> for F
where
F: FnOnce(&'a HashSet<usize>, &'a HashSet<usize>) -> T,
T: Iterator<Item = &'a usize> + 'a,
{
type Output = T;
fn call(self, a: &'a HashSet<usize>, b: &'a HashSet<usize>) -> T {
// Delegate to FnOnce
self(a, b)
}
}
struct Foo {
data: HashSet<usize>,
}
impl Foo {
fn test<F>(&mut self, _operation: F) -> ()
where
F: for<'a> IteratorCallback<'a>,
{
let update: HashSet<usize> = vec![4, 2, 9].into_iter().collect();
self.data = _operation.call(&self.data, &update).copied().collect();
}
fn new() -> Self {
Foo {
data: HashSet::new(),
}
}
}
fn main() {
let mut foo: Foo = Foo::new();
foo.test(HashSet::intersection);
}
Note: I changed the function bound to FnOnce because that's more permissive than Fn and all you need in this case, but the same technique will work with Fn as long as you change fn call(self, to fn call(&self,.
Credit: I used this Reddit comment by user Lej77 as an example to work from for the trait technique.
Broadly speaking my goal is this:
For some known type Bar...
Have a trait Foo with a function: get_iterator<T>() -> T where T: Iterator<Item = Bar>
The instance of the iterator borrows the original object Foo is implemented on.
I imagine it working like this:
let mut foo = Foo;
let bar = foo.get_iterator();
foo.mutable_call(); // <-- This fails, because foo is borrowed in bar
for x in bar {
...
}
So, that's the goal, and here's my attempt, which I can't seem to get working:
struct ValsFromT<'a, T: 'a> {
parent:&'a T,
offset: usize,
}
struct Val;
trait HasValsIterator<T> {
fn val_iterator(&self) -> T where T: Iterator<Item = Val>;
}
struct Foo;
impl<'a> Iterator for ValsFromT<'a, Foo> {
type Item = Val;
fn next(&mut self) -> Option<Val> {
return None;
}
}
impl<'a> HasValsIterator<ValsFromT<'a, Foo>> for Foo {
fn val_iterator(&'a self) -> ValsFromT<'a, Foo> {
return ValsFromT {
offset: 0usize,
parent: self
};
}
}
fn takes_vals<T>(instance:T) where T: HasValsIterator<T> {
// ...
}
#[test]
fn test_foo() {
let x = Foo;
takes_vals(x);
}
(playpen: http://is.gd/wys3fx)
We're getting the dreaded concrete/bound lifetime error here, because of trying to return an iterator instance that references self from the trait function:
<anon>:22:3: 27:4 error: method `val_iterator` has an incompatible type for trait:
expected bound lifetime parameter ,
found concrete lifetime [E0053]
<anon>:22 fn val_iterator(&'a self) -> ValsFromT<'a, Foo> {
<anon>:23 return ValsFromT {
<anon>:24 offset: 0usize,
<anon>:25 parent: self
<anon>:26 };
<anon>:27 }
<anon>:22:3: 27:4 help: see the detailed explanation for E0053
Is there some way of doing this?
Unfortunately, Veedrac's suggestion doesn't work directly. You will get the following error if you'd try to use val_iterator() method on instance inside takes_vals():
<anon>:31:25: 31:39 error: the trait `core::iter::Iterator` is not implemented for the type `U` [E0277]
<anon>:31 let iter = instance.val_iterator();
^~~~~~~~~~~~~~
<anon>:31:25: 31:39 help: see the detailed explanation for E0277
<anon>:31:25: 31:39 note: `U` is not an iterator; maybe try calling `.iter()` or a similar method
error: aborting due to previous error
playpen: application terminated with error code 101
This (and some other further errors) requires changing the signature of the function to this one:
fn takes_vals<'a, T: 'a, U: Iterator<Item=Val>+'a>(instance: T) where T: HasValsIterator<'a, U>
However, even this doesn't work yet:
<anon>:31:16: 31:24 error: `instance` does not live long enough
<anon>:31 let iter = instance.val_iterator();
^~~~~~~~
<anon>:30:97: 32:2 note: reference must be valid for the lifetime 'a as defined on the block at 30:96...
<anon>:30 fn takes_vals<'a, T: 'a, U: Iterator<Item=Val>+'a>(instance: T) where T: HasValsIterator<'a, U> {
<anon>:31 let iter = instance.val_iterator();
<anon>:32 }
<anon>:30:97: 32:2 note: ...but borrowed value is only valid for the scope of parameters for function at 30:96
<anon>:30 fn takes_vals<'a, T: 'a, U: Iterator<Item=Val>+'a>(instance: T) where T: HasValsIterator<'a, U> {
<anon>:31 let iter = instance.val_iterator();
<anon>:32 }
Remember that the trait requires that val_iterator() accepts the target by reference with lifetime 'a. This lifetime in this function is an input parameter. However, when val_iterator() is called on instance, the only lifetime which can be specified for the reference is the one of instance which is strictly smaller than any possible 'a as a parameter, because it is a local variable. Therefore, it is not possible to pass instance by value; you can only pass it by reference for lifetimes to match:
fn takes_vals<'a, T: 'a, U: Iterator<Item=Val>+'a>(instance: &'a T) where T: HasValsIterator<'a, U> {
let iter = instance.val_iterator();
}
This works.
I'd like to add that using associated types instead of type parameters would be more correct semantically:
trait HasValsIterator<'a> {
type Iter: Iterator<Item=Val> + 'a;
fn val_iterator(&'a self) -> Self::Iter;
}
impl<'a> HasValsIterator<'a> for Foo {
type Iter = ValsFromT<'a, Foo>;
fn val_iterator(&'a self) -> ValsFromT<'a, Foo> { ... }
}
fn takes_vals<'a, T: 'a>(instance: &'a T) where T: HasValsIterator<'a> {
...
}
I say that this is more correct because the type of the iterator is determined by the implementor, that is, it is "output" type, which are modeled by associated types. As you can see, takes_vals() signature also shrank considerably.
Ideally, HasValsIterator trait should have been defined like this:
trait HasValsIterator {
type Iter<'a>: Iterator<Item=Val> + 'a
fn val_iterator<'a>(&'a self) -> Iter<'a>;
}
This way, val_iterator() would in any situation, including when HasValsIterator implementor is passed by value. However, Rust is not there yet.
I have a lifetime issue, I'm trying to implement an iterator returning its items by reference, here is the code:
struct Foo {
d: [u8; 42],
pos: usize
}
impl<'a> Iterator<&'a u8> for Foo {
fn next<'a>(&'a mut self) -> Option<&'a u8> {
let r = self.d.get(self.pos);
if r.is_some() {
self.pos += 1;
}
r
}
}
fn main() {
let mut x = Foo {
d: [1; 42],
pos: 0
};
for i in x {
println!("{}", i);
}
}
However this code doesn't compile properly, I get an issue related to the lifetime of parameters, here is the corresponding error:
$ rustc test.rs
test.rs:8:5: 14:6 error: method `next` has an incompatible type for trait: expected concrete lifetime, but found bound lifetime parameter
test.rs:8 fn next<'a>(&'a mut self) -> Option<&'a u8> {
test.rs:9 let r = self.d.get(self.pos);
test.rs:10 if r.is_some() {
test.rs:11 self.pos += 1;
test.rs:12 }
test.rs:13 r
...
test.rs:8:49: 14:6 note: expected concrete lifetime is the lifetime 'a as defined on the block at 8:48
test.rs:8 fn next<'a>(&'a mut self) -> Option<&'a u8> {
test.rs:9 let r = self.d.get(self.pos);
test.rs:10 if r.is_some() {
test.rs:11 self.pos += 1;
test.rs:12 }
test.rs:13 r
...
error: aborting due to previous error
Does somebody has an idea how to fix this issue and still returning items by reference?
At least what does this message means: expected concrete lifetime, but found bound lifetime parameter ?
Note on the version of Rust used: at the time this question and answer were written, the Iterator trait used generics; it has changed to use associated types and is now defined thus:
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
…
}
And so the incorrect implementation shown here would be like this:
impl<'a> Iterator for Foo {
type Item = &'a u8;
fn next<'a>(&'a mut self) -> Option<&'a u8>;
}
In practical terms this affects nothing; it is merely that A becomes Self::Item.
The definition of the Iterator trait is thus:
pub trait Iterator<A> {
fn next(&mut self) -> Option<A>;
…
}
Note carefully: fn next(&mut self) -> Option<A>.
Here is what you have:
impl<'a> Iterator<&'a u8> for Foo {
fn next<'a>(&'a mut self) -> Option<&'a u8>;
}
Note carefully: fn next<'a>(&'a mut self) -> Option<&'a u8>.
There are several problems here:
You have introduced a new generic parameter <'a> which should not be there. For convenience’s sake and to emphasise what has happened here, I shall dub the 'a defined on the impl block ρ₀ and the 'a defined on the method ρ₁. They are not the same.
The lifetime of &mut self is different from that of the trait.
The lifetime of the return type is different to the trait: where A is &'ρ₀ u8, the return type uses in the place of A &'ρ₁ u8. It expected the concrete lifetime ρ₀ but found instead the lifetime ρ₁. (I’m not certain precisely what the “bound” bit means, so I’ll keep quiet on it lest I be wrong.)
Here’s what this amounts to: you cannot connect the lifetime of the object you are iterating over to &mut self. Instead, it must be bound to something in the type you are implementing the trait for. To take an example, iterating over items in a slice is done by creating a new iterator object connected to the base slice, impl<'a, T> Iterator<&'a T> for Items<'a, T>. Expressed in another way, the way the iteration traits are designed is not, if you are producing references, for you to return something inside self, but rather to return something inside another object that you have a reference to.
For your specific, presumably simple example, you should either stop yielding references, or alter it so that your iterator object does not contain the data that you are iterating over—let it merely contain a reference to it, e.g. &'a [T] or even something like Items<'a, T>.
I’m having trouble using a generic function that takes a generic trait object as a parameter. When I try to call the function, the compiler complains “error: the trait Next is not implemented for the type &'a mut Next<Type=Type> + 'a [E0277]”. In my opinion, the Next trait is object-safe for any parameter Type, so Next should be implemented by any &Next<Type> (by my reading of Huon’s Object-Safety article); is there any way to check that it is object-safe?
Incidentally, I’m having no problem doing pretty much the same thing with an Iterator, and I don’t know how that is different.
trait Next {
type Type;
fn next(&mut self) -> Option<Self::Type>;
}
struct NextImpl<Type> {
next: Option<Type>,
}
impl<Type> Next for NextImpl<Type> {
type Type = Type;
fn next(&mut self) -> Option<Self::Type> {
let mut ret = None;
std::mem::swap(&mut self.next, &mut ret);
ret
}
}
struct DelegatingNext<'a, Type> {
delegate: &'a mut Next<Type=Type>,
}
impl<'a, Type> Next for DelegatingNext<'a, Type> {
type Type = Type;
fn next(&mut self) -> Option<Self::Type> {
self.delegate.next()
// error: the trait `Next` is not implemented for the type `&'a mut Next<Type=Type> + 'a` [E0277]
// Next::next(&mut self.delegate)
// ^~~~~~~~~~
// error: the trait `Next` is not implemented for the type `&'a mut Next<Type=Type> + 'a` [E0277]
// if (true) {
// next_next1(&mut self.delegate)
// ^~~~~~~~~~
// error: the trait `Next` is not implemented for the type `&'a mut Next<Type=Type> + 'a` [E0277]
// next_next2(&mut self.delegate)
// ^~~~~~~~~~~~~~~~~~
}
}
fn next_next1<'a, NextType: Next + ?Sized>(m: &'a mut NextType) -> Option<NextType::Type> {
m.next()
}
fn next_next2<'a, Type>(m: &'a mut Next<Type=Type>) -> Option<Type> {
m.next()
}
struct DelegatingIterator<'b, T> {
iter: &'b mut Iterator<Item=T>,
}
impl<'b, T> DelegatingIterator<'b, T> {
fn next(&mut self) -> Option<T> {
let iter: &mut Iterator<Item=T> = self.iter;
iterator_next1(iter)
// error: the trait `core::marker::Sized` is not implemented for the type `core::iter::Iterator<Item=T>` [E0277]
// note: `core::iter::Iterator<Item=T>` does not have a constant size known at compile-time
// iterator_next2(iter)
// ^~~~~~~~~~~~~~
// OK
// iterator_next3(iter)
// OK
// iterator_next4(iter)
}
}
fn iterator_next1<'a, T>(iter: &mut Iterator<Item=T>) -> Option<T> {
iter.next()
}
fn iterator_next2<It: Iterator>(iter: &mut It) -> Option<It::Item> {
iter.next()
}
fn iterator_next3<It: Iterator + ?Sized>(iter: &mut It) -> Option<It::Item> {
iter.next()
}
fn iterator_next4<'a, Item>(iter: &mut Iterator<Item=Item>) -> Option<Item> {
iter.next()
}
fn main() {
let mut m = NextImpl {next: Some("hi")};
let mut delegating_model = DelegatingNext {delegate: &mut m};
assert!(Some("hi") == delegating_model.next());
let v: Vec<i32> = vec!(1, 2, 3);
let mut iter = v.iter();
assert_eq!(Some(&1), (DelegatingIterator {iter: &mut iter }).next());
}
I think you are adding an extra layer of indirection. The method call self.delegate.next() desugars into Next::next(self.delegate) in this case - no automatic referencing (mutable or otherwise) is needed.
The error message is confusing because you have two levels of reference. Your trait is written:
trait Next {
fn next(&mut self)
}
Which means that you always have to pass in a &mut Foo. However, you were taking a second mutable reference, making the argument type &mut &mut NextImpl<Type>. The first &mut is matched by the function parameter, but then the rest of the type needs to implement Next. However, &mut NextImpl<Type> does not implement that trait, only NextImpl<Type> does!
Your Sized problem is very similar. The function is defined as
fn iterator_next2<It: Iterator>(iter: &mut It) -> Option<It::Item>
That is, it expects a mutable reference to some concrete type that implements Iterator. Your call passes a &mut Iterator - a trait object. A trait object is a reference to something without a known size, it is only known to implement the methods of the trait. Since you don't care about the size of the thing being referred to, the correct option is to declare that, as you did:
fn iterator_next3<It: Iterator + ?Sized>(iter: &mut It) -> Option<It::Item> {
iter.next()
}
This is super confusing, so let me know if I need to attempt to explain it differently.