Reputation: 5390
The following
use std::borrow::Borrow;
trait DictLike<'a> {
type Label: Eq + 'a;
type ItemsIterator: Iterator<Item=(&'a Self::Label, &'a DictLike<'a>)> + 'a;
fn items(&self) -> Self::ItemsIterator;
fn get<Q: ?Sized + Eq>(&self, key: &Q) -> Option<&'a DictLike<'a>>
where Self::Label: Borrow<Q> {
for (k,v) in self.items() {
if k.borrow().eq(key) {
return Some(v);
}
}
None
}
}
errors out as
lib.rs:12:16: 12:26 error: the type of this value must be known in this context
lib.rs:12 if k.borrow().eq(key) {
^~~~~~~~~~
Why? Doesn't ItemsIterator
's type bound and the bound Self::Label: Borrow<Q>
provide the necessary type information?
Upvotes: 1
Views: 160
Reputation: 102306
This seems like a bug: the <'a>
in the trait declaration is seemingly causing the compiler to get confused, e.g.:
trait DictLike<'a> {
type ItemsIterator: Iterator<Item=u8>;
fn items(&self) -> Self::ItemsIterator;
fn get(&self) {
for k in self.items() {}
}
}
<anon>:7:13: 7:14 error: unable to infer enough type information about `_`; type annotations required [E0282]
<anon>:7 for k in self.items() {}
^
Removing the 'a
allows that code to compile. I've filed #24338 about this.
Fortunately, there is a work around: this seems to only happen when the code is inside the default method, and moving the actual implementation to an external function works fine:
use std::borrow::Borrow;
trait DictLike<'a> {
type Label: Eq + 'a;
type ItemsIterator: Iterator<Item=(&'a Self::Label, &'a DictLike<'a>)> + 'a;
fn items(&self) -> Self::ItemsIterator;
fn get<Q: ?Sized + Eq>(&self, key: &Q) -> Option<&'a DictLike<'a>>
where Self::Label: Borrow<Q> {
get(self, key)
}
}
fn get<'a, X: ?Sized + DictLike<'a>, Q: ?Sized + Eq>(x: &X, key: &Q) -> Option<&'a DictLike<'a>>
where X::Label: Borrow<Q> {
for (k,v) in x.items() {
if k.borrow() == key {
return Some(v);
}
}
None
}
This is functionally no different to the original code, except for the fact that it compiles. (I took the liberty of switching the .eq
call to the ==
operator, which is nicer sugar for the method call.)
Also, if you're feeling like experimenting with iterators a little more, one could write get
as
x.items()
.find(|&(k,_)| k.borrow() == key)
.map(|(_, v)| v)
Using Iterator::find
and Option::map
.
Upvotes: 3