nir shahar
nir shahar

Reputation: 368

Converting a method that borrows an item into one that takes ownership over it

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

Answers (2)

Finomnis
Finomnis

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

jthulhu
jthulhu

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

Related Questions