[Solved] Implementing a trait for function/closure types

Hi,

this probably came up already, though I couldn't find the information by searching.
I have trait with a single function and it would be nice if I could also pass a function/closure with a compatible signature, e.g., if no state is needed to implement the functionality.

Of course I could also accept a function type like Fn(T) -> T but semantically other structs implementing the trait shouldn't be passed to functions accepting just a function type. So its similar to a newtype, but with more flexibility in the implementation.

The code currently looks like this, compiling as expected:

trait MyTrait<T> {
    fn foo(&mut self, x: &T) -> T;
}

impl<T> MyTrait<T> for FnOnce(&T) -> T {
    fn foo(&mut self, x: &T) -> T {
        self(x)
    }
}

I decided to implement the trait for FnOnce s.t. FnMut and Fn are also covered.
Though when I try to use it:

fn bar<F>(f: F) where F: MyTrait<i32> {
    println!("{}", f.foo(&2));
}

fn main() {
    bar(|&x: &i32| x*2);
}

... the compiler complains that the closure does not implement MyTrait<i32>:

  --> main.rs:19:5
   |
19 |     bar(|x| x*2);
   |     ^^^ the trait `MyTrait<i32>` is not implemented for `[closure@main.rs:19:9: 19:16]`
   |
   = note: required by `bar`

Shouldn't the closure be covered by the FnOnce implementation?

3 Likes

OK, got it. I shouldn't implemnt it for the FnOnce trait but for a type implementing FnOnce.
Actually I have to use FnMut as FnOnce moves self out of the borrowed content.

So the working code is:

trait MyTrait<T> {
    fn foo(&mut self, x: &T) -> T;
}

impl<T, F> MyTrait<T> for F where F: FnMut(&T) -> T {
    fn foo(&mut self, x: &T) -> T {
        self(x)
    }
}

fn bar<F>(mut f: F) where F: MyTrait<i32> {
    println!("{}", f.foo(&2));
}

fn main() {
    bar(|&x: &i32| x*2);
}

I should still reason about the signature of my trait to allow FnOnce types

8 Likes