Reputation: 38978
I’m trying to extract a function from a struct. The original (working) is:
pub fn f(&self, id: Id) -> &[Foo] {
self.foos.get(&id).map_or(&[], |foos| &**foos)
}
Where where self.foos
is a HashMap<Id, Vec<Foo>, BuildHasherDefault<FnvHasher>>
After extraction I have
fn f<'a>(foos: HashMap<Id, Vec<Foo>, BuildHasherDefault<FnvHasher>>, id: Id) -> &'a [Foo] {
&foos.get(&id).map_or(&[], |xs| &**xs);
}
The resulting error is
error: mismatched types:
expected `&[_; 0]`,
found `&[foo::Foo]`
(expected array of 0 elements,
found slice) [E0308]
I think I need to provide a type hint. Is this right? If so, how do I explicitly declare the type of U
when calling Option.map_or<U, F>(self, default: U, f: F) -> U
Upvotes: 1
Views: 1125
Reputation: 65782
The error you're getting hides the real issues with the code. In situations like this, by being more explicit, the compiler can get further and give other errors that are more relevant to solving the problem.
First, let's get rid of the type mismatch by explicitly converting the array to a slice, by changing &[]
to &[][..]
.
fn f<'a>(foos: HashMap<Id, Vec<Foo>, BuildHasherDefault<FnvHasher>>, id: Id) -> &'a [Foo] {
&foos.get(&id).map_or(&[][..], |xs| &**xs);
}
We're now getting this error:
error: not all control paths return a value [--explain E0269]
--> <anon>:16:1
|>
16 |> fn f<'a>(foos: HashMap<Id, Vec<Foo>, BuildHasherDefault<FnvHasher>>, id: Id) -> &'a [Foo] {
|> ^
Ah ha! There's a semicolon at the end of the function that shouldn't be there. Let's remove it.
fn f<'a>(foos: HashMap<Id, Vec<Foo>, BuildHasherDefault<FnvHasher>>, id: Id) -> &'a [Foo] {
&foos.get(&id).map_or(&[][..], |xs| &**xs)
}
Mmm, still not compiling:
error: `foos` does not live long enough
--> <anon>:17:6
|>
17 |> &foos.get(&id).map_or(&[][..], |xs| &**xs)
|> ^^^^
note: reference must be valid for the lifetime 'a as defined on the block at 16:90...
--> <anon>:16:91
|>
16 |> fn f<'a>(foos: HashMap<Id, Vec<Foo>, BuildHasherDefault<FnvHasher>>, id: Id) -> &'a [Foo] {
|> ^
note: ...but borrowed value is only valid for the scope of function body at 16:90
--> <anon>:16:91
|>
16 |> fn f<'a>(foos: HashMap<Id, Vec<Foo>, BuildHasherDefault<FnvHasher>>, id: Id) -> &'a [Foo] {
|> ^
Basically, the error is that you're trying to return a borrowed pointer into a HashMap
that will be destroyed at the end of the call to f
(because the HashMap
is passed by value). You need to pass the HashMap
by reference. We can get rid of the unnecessary [..]
now, because it compiles!
fn f(foos: &HashMap<Id, Vec<Foo>, BuildHasherDefault<FnvHasher>>, id: Id) -> &[Foo] {
foos.get(&id).map_or(&[], |xs| &**xs)
}
Upvotes: 8