I've found a weird edge case (?) in implementing traits for functions (that is fn, function pointers). I've created a minimal example here: Rust Playground. The following code doesn't compile:
pub trait MyTrait {
type Argument;
type Result;
fn call(&mut self, arg: Self::Argument) -> Self::Result;
}
impl<Arg, R> MyTrait for fn(Arg) -> R {
type Argument = Arg;
type Result = R;
fn call(&mut self, arg: Self::Argument) -> Self::Result {
(self)(arg)
}
}
fn main() {
direct(convert(fn1));
// This won't compile?
// However the "convert" function just returns its argument.
direct(fn1);
println!("Ok");
}
fn fn1(_: ()) -> usize { 1 }
fn convert<Arg, R>(f: fn(Arg) -> R) -> impl MyTrait<Argument = Arg, Result = R> {
f
}
fn direct<T: MyTrait>(_f: T) { }
Am I missing something or is this a bug? Any help would be appreciated, thank you.
fn1, as written, isn't an fn pointer, it's an "fn item" - that is, it's a reference to that specific function. You need to cast it to be an fn pointer, e.g.:
Or can I change the impl MyTrait for fn(Arg) -> R to work with fn1 directly? I know of the Fn and related trait, but those won't work in the actual code I'm working with.
Perhaps you can just impl MyTrait for a closure, i.e.:
impl<F, R> MyTrait for F where F: FnMut(()) -> R {
type Argument = ();
type Result = R;
fn call(&mut self, _: Self::Argument) -> Self::Result {
(self)(())
}
}
I want to thank everybody one last time for all the replies. I decided to go with letting the users convert the function items into pointer (i.e. `my_fn as fn(_) -> _) themselves as @vitalyd suggested.
I do think it's to bad that Into doesn't include this coercion because that would fix all my problems by changing the generic bound to T: Into<MyTrait>.