Reputation: 368
I want to know if rust can automatically coerce a function that implements Fn(&X) -> Y
into a function that implements Fn(X) -> Y
.
More specifically, I have a higher-order function with the following signature:
fn do_stuff<Y, F: Fn(i32) -> Y>(action: F) {
// Does some stuff with the method (specifically, move it into a Box)
}
and I want to be able to call it like so:
do_stuff(i32::to_string)
instead of the current
do_stuff(|x| x.to_string())
However, I'm getting the following error:
expected function signature
fn(i32) -> _
,found function signature
for<'r> fn(&'r i32) -> _
.
I figure this is because the function i32::to_string
borrows &self
as a parameter, while the closure takes ownership over it.
Is there a way that I can change the signature of do_stuff
so that I can also call it in that way?
Here is a reproduction of the issue in the rust playground.
Upvotes: 2
Views: 205
Reputation: 22501
Technically this works:
use std::borrow::Borrow;
fn do_stuff<X, Y, F: Fn(X) -> Y>(action: F)
where
X: Borrow<i32>,
{
// Does some stuff with the method (specifically, move it into a Box)
}
fn bla(x: i32) {}
fn bla_ref(x: &i32) {}
fn main() {
do_stuff(i32::to_string);
do_stuff(bla);
do_stuff(bla_ref);
}
Although it's pretty much normal to use the |x| x.do_something()
closures regularly, so I wouldn't worry about it too much.
Upvotes: 3
Reputation: 8678
There is no way to implicitly coerce Fn(&T) -> U
into Fn(T) -> U
, because it's just not among the implicit coercions Rust will allow. However, there is a way to factor out the repetitive code:
fn add_ref<T, U>(f: impl Fn(&T) -> U) -> impl Fn(T) -> U {
move |ref x| f(x)
}
It works on (a minimized version of) your example:
fn do_stuff<Y, F: Fn(i32) -> Y>(_: F) {}
fn main() {
do_stuff(add_ref(i32::to_string))
// do_stuff(i32::to_string)
// ^^^^^^^^^^^^^^^^^^^^^^^^ this would fail
}
see the playground.
Upvotes: 3