How to convert a generic function into a function pointer with a reference parameter?

Viewed 374
pub fn remove_file<P: AsRef<Path>>(path: P) -> Result<()>;

I am struggling to cast std::fs::remove_file to a function pointer: Playground

use std::{io, fs, path::Path};

fn main() {
    let _:  fn(&Path) -> io::Result<()> = &fs::remove_file;

    // let _: &dyn FnOnce(&Path) -> io::Result<()> = &fs::remove_file;
}

The error is the following:

error[E0308]: mismatched types
 --> src/main.rs:4:43
  |
4 |     let _:  fn(&Path) -> io::Result<()> = &fs::remove_file;
  |             ---------------------------   ^^^^^^^^^^^^^^^^ expected fn pointer, found reference
  |             |
  |             expected due to this
  |
  = note: expected fn pointer `for<'r> fn(&'r std::path::Path) -> std::result::Result<(), std::io::Error>`
              found reference `&fn(_) -> std::result::Result<(), std::io::Error> {std::fs::remove_file::<_>}`

The problem might be with the for<'r> higher-order lifetimes requirement, but I don't know how to solve it.

How would I do it with a trait object? The following doesn't compile either:

let _: &dyn FnOnce(&Path) -> io::Result<()> = &fs::remove_file;

I know I can make a wrapper function around fs::remove_file, but I'd like to avoid that and get fs::remove_file to become a function pointer or trait object itself.

This is not a duplicate of this Function pointers in Rust using constrained generics as I'd like to get a function pointer to the concrete instantiation of std::fs::remove_file with &Path as a type parameter, but not to have a generic function pointer type.

I tried the following and it doesn't work either:

use std::{io, fs, path::Path};

fn main() {
    let _:  fn(&Path) -> io::Result<()> = &fs::remove_file::<&Path>;
}
1 Answers

I'd like to get a function pointer to the concrete instantiation of std::fs::remove_file with &Path as a type parameter, but not to have a generic function pointer type.

This is the heart of the issue. A concrete instantiation will compile. For example:

let _ : fn(&'static Path) -> io::Result<()> = fs::remove_file::<&'static Path>;
let _ : fn(&'r Path) -> io::Result<()> = fs::remove_file::<&'r Path>;
let _ : fn(&'long Path) -> io::Result<()> = fs::remove_file::<&'short Path>;

What you are trying to do is coerce from fs::remove_file of type:

∀ P: AsRef<Path>, P → io::Result<()>

to the type:

∀ 'r, &'r Path → io::Result<()>

The function pointer type is still generic over the lifetime. I don't think there's a reason this coercion couldn't be done, but Rust has some issues in this area.

The most straightforward workaround that Rust understands is to use a closure:

let _ : fn(&Path) -> io::Result<()> = |p| fs::remove_file(p);
Related