Use Generics in closure

I am trying to write a function similar to use_generic_offset. I am not able to define a closure which accepts parameter that implements a trait. Any ideas how to fix it?

trait Offset{}

impl Offset for i32{}
impl Offset for i64{}

struct GenericOffset<O: Offset> {
    inner: O
}

fn use_generic_offset<O: Offset, F>(
    param1: u32,
    cls: F,
)
where
    F: Fn(GenericOffset<O>) -> ()
{
    if param1 == 1 {
        let cls_param = get_generic_i32();
        cls(cls_param);
    } else {
        let cls_param = get_generic_i64();
        cls(cls_param);
    }
}

fn get_generic_i32() -> GenericOffset<i32> {
    GenericOffset{
        inner: 4
    }
}
fn get_generic_i64() -> GenericOffset<i64> {
    GenericOffset{
        inner: 4
    }
}

fn main() {
    println!("Hello, world!");
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
  --> src/main.rs:19:13
   |
10 | fn use_generic_offset<O: Offset, F>(
   |                       - this type parameter
...
19 |         cls(cls_param);
   |         --- ^^^^^^^^^ expected type parameter `O`, found `i32`
   |         |
   |         arguments to this function are incorrect
   |
   = note: expected struct `GenericOffset<O>`
              found struct `GenericOffset<i32>`
note: callable defined here
  --> src/main.rs:15:8
   |
15 |     F: Fn(GenericOffset<O>) -> ()
   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0308]: mismatched types
  --> src/main.rs:22:13
   |
10 | fn use_generic_offset<O: Offset, F>(
   |                       - this type parameter
...
22 |         cls(cls_param);
   |         --- ^^^^^^^^^ expected type parameter `O`, found `i64`
   |         |
   |         arguments to this function are incorrect
   |
   = note: expected struct `GenericOffset<O>`
              found struct `GenericOffset<i64>`
note: callable defined here
  --> src/main.rs:15:8
   |
15 |     F: Fn(GenericOffset<O>) -> ()
   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to 2 previous errors

Rust doesn't support generics for closures. The thing you can do instead is create your own trait with a generic method of the desired signature (plus a &selfargument if you want to support the equivalent of variable capture in Fn(…)), and then pass an instance of that trait instead of an instance of some Fn trait. You'll lose the benefit of closure syntax and automatic variable captures, but in principle, it's possible to express everything that one would need to express.

5 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.